M-V-VM,是不是模型泄漏到视图中?

时间:2010-04-14 22:13:18

标签: c# wpf mvvm

众所周知,M-V-VM的重点在于关注的问题。在MVVM,MVC或MVP等模式中,主要目的是将View与Data分离,从而构建更灵活的组件。我将首先演示在许多WPF应用程序中找到的非常常见的场景,然后我会说明一点:

假设我们有一些StockQuote应用程序可以流式传输一堆引号并在屏幕上显示它们。通常,你有这个:

StockQuote.cs :(型号)

    public class StockQuote
    {
       public string Symbol { get; set; }
       public double Price { get; set; }
    }

StockQuoteViewModel.cs :( ViewModel)

   public class StockQuoteViewModel
   {
      private ObservableCollection<StockQuote> _quotes = new ObservableCollection<StockQuote>();

      public ObservableCollection<StockQuote> Quotes 
      {
         get
         {
            return _quotes;
         }
      }
   }

StockQuoteView.xaml(查看)

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="Window1" Height="300" Width="300">
    <Window.DataContext>
        <local:StockQuoteViewModel/>
    </Window.DataContext>
    <Window.Resources>
        <DataTemplate x:Key="listBoxDateTemplate">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Symbol}"/>
                <TextBlock Text="{Binding Price}"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ListBox ItemTemplate="{StaticResource listBoxDateTemplate}" ItemsSource="{Binding Quotes}"/>
    </Grid>
</Window>

然后你会得到某种服务,用新的StockQuotes为ObservableCollection提供服务。

我的问题是:在这种情况下,StockQuote被认为是Model,我们通过ViewModel的ObservableCollection将它暴露给View。这基本上意味着,我们的View拥有模型的知识。这是否违反了M-V-VM的整个范式?或者我在这里错过了什么......?

6 个答案:

答案 0 :(得分:8)

我比MVVM更熟悉MVC,但是人们普遍认为View会知道模型。只要模型不了解View就可以了。

如果出于某种原因这确实是一个问题,请查看“被动视图”设计,其中View只知道提供给它的原始数据。

答案 1 :(得分:7)

在MVVM中,视图模型位于视图和模型之间,它以一种可以由视图轻松处理的方式公开模型中的数据。在严格的MVVM应用程序中,视图不了解模型,只知道视图模型。

在您的具体示例中,视图模型不应该被称为StockQuoteViewModel而是StockQuotesViewModel(注意复数),因为视图模型通过特定的ui集合公开了许多股票报价,这很容易视图处理(因为ObservableCollection<T>实现INotifyCollectionChanged<T>)。集合中的项目类型应该是一个视图模型(例如StockQuoteViewModel),它公开来自单个StockQuote对象的数据。在这样的视图模型中,您可以添加逻辑,例如向$添加Price - 符号,依此类推。

在视图模型中公开一些模型对象通常更容易,但正确的方法是为每个模型类创建一个视图模型。

最诚挚的问候,
Oliver Hanappi

答案 2 :(得分:3)

没有。您没有暴露StockQuote。您只是在视图中指定(松散类型)接口。视图只知道两个属性:符号和价格。只要它实现了那些,你就可以轻松地用其他任何东西替换StockQuote。

答案 3 :(得分:3)

查看视频:Jason Dolinger on MVVM。它会回答你的问题。

另外,请参阅问题wpf mvvm confusion以获取更多资源。

答案 4 :(得分:1)

我的理解是,ViewModel属于模型,属性属于Fields。这是一个非常宽松的类比,但如果您的View直接访问您的模型,它确实意味着您没有正确隔离。就像包装私有字段的类中的普通属性一样,在ViewModel属性中包含相关的Model属性以供View使用时,最终会得到大量的复​​制和样板代码。这种情况困扰着我,我仍然没有决定这些好处是否值得臃肿。

在这个特定的例子中,我认为为每个StockQuote实例创建一个VM会有点过分,因为您可能没有为代表单个StockQuote的View做任何重要逻辑。我认为在这些小的情况下,直接绑定到Model类会更清晰,更易于维护。为小案例创建VM会减少耦合,但这也会增加复杂性,我认为这是一个判断是否有益的判断调用。

答案 5 :(得分:0)

也许我有这个错误,但不是完全封装模型的viewmodel的想法。例如,您有暴露给视图的股票报价,但它们应该映射到viewmodel本机的属性,然后绑定到该属性。这是为了在将数据传输到模型/视图期间可能需要“清理”。

这样,视图才知道视图模型。这也意味着如果模型不是遗留的,它可以作为接口实现,并进一步减少视图模型之间的耦合。