【问题标题】:M-V-VM, isn't the Model leaking into the View?M-V-VM,模型不是泄漏到视图中了吗?
【发布时间】:2010-04-14 22:13:17
【问题描述】:

众所周知,M-V-VM 的意义在于分散关注点。在 MVVM、MVC 或 MVP 等模式中,主要目的是将视图与数据分离,从而构建更灵活的组件。我将首先演示在许多 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>

然后您将获得某种服务,该服务将向 ObservableCollection 提供新的 StockQuotes。

我的问题是:在这种情况下,StockQuote 被视为模型,我们通过 ViewModel 的 ObservableCollection 将其公开给视图。这基本上意味着,我们的视图了解模型。这不违反 M-V-VM 的整个范式吗?还是我在这里遗漏了什么......?

【问题讨论】:

    标签: c# wpf mvvm


    【解决方案1】:

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

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

    【讨论】:

    • 正是我要输入的内容。视图必须了解模型的某些内容,否则它的视图是什么?
    【解决方案2】:

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

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

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

    最好的问候,
    奥利弗·哈纳皮

    【讨论】:

      【解决方案3】:

      没有。您没有公开 StockQuote。您只是在视图中指定一个(松散类型的)接口。该视图只知道两个属性:Symbol 和 Price。您可以轻松地将 StockQuote 替换为其他任何东西,只要它实现了这些。

      【讨论】:

      • 这很好,尽管它依赖于 WPF 数据绑定的“松散”性质。但是,如果您为依赖于 StockQuote 集合的 VM 编写了一个单元测试,那么如果您更改 StockQuote 类,它就会中断。
      【解决方案4】:

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

      另外,请参阅 SO 问题 wpf mvvm confusion 了解更多资源。

      【讨论】:

        【解决方案5】:

        我的理解是,ViewModels 之于 Models 就像 Properties 之于 Fields。这是一个非常松散的类比,但它确实意味着如果您的 View 直接访问您的 Model,则您没有正确隔离。就像包装私有字段的类中的琐碎属性一样,在将相关模型属性包装在 ViewModel 属性中以供 View 使用时,最终会产生大量重复和样板代码。这种模式困扰着我,我仍然不确定这些好处是否值得膨胀。

        在这个特定的示例中,我认为为每个 StockQuote 实例创建一个 VM 有点过头了,因为您可能不会为表示单个 StockQuote 的视图执行任何重要的逻辑。我认为在这些小案例中,直接绑定到 Model 类会更简洁、更易于维护。为小案例创建 VM 会减少耦合,但也会增加复杂性,我认为这是否有益需要根据具体情况进行判断。

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-04-10
            • 2010-09-25
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多