开发者

M-V-VM, isn't the Model leaking into the View?

开发者 https://www.devze.com 2022-12-26 17:06 出处:网络
The point of M-V-VM as we all know is about speraration of concerns. In patterns like MVVM, MVC or MVP, the main purpose is to decouple the View from the Data thereby building more flexible components

The point of M-V-VM as we all know is about speraration of concerns. In patterns like MVVM, MVC or MVP, the main purpose is to decouple the View from the Data thereby building more flexible components. I'll demonstrate first a very common scenario found in many WPF apps, and then I'll make my point:

Say we have some StockQuote application that streams a bunch of quotes and displays them on screen. Typically, you'd have this:

StockQuote.cs : (Model)

    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 (View)

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmln开发者_如何转开发s: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>

And then you'd have some kind of service that would feed the ObservableCollection with new StockQuotes.

My question is this: In this type of scenario, the StockQuote is considered the Model, and we're exposing that to the View through the ViewModel's ObservableCollection. Which basically means, our View has knowledge of the Model. Doesn't that violate the whole paradigm of M-V-VM? Or am I missing something here....?


I'm more familiar with MVC than MVVM, but it's generally accepted that the View will have knowledge of the Model. As long as the Model has no knowledge of the View this is okay.

If this really is a concern for whatever reason, check out the "Passive View" design, where the View knows nothing more than the raw data fed to it.


In MVVM the view model is something in between the view and the model which exposes data from the model in a way that can be handled easily by the view. In a strict MVVM application the view does not know about the model, only about the view model.

In your concrete example the view model should not be called StockQuoteViewModel but StockQuotesViewModel (be aware of the plural) because the view model is exposing many stock quotes by a specific ui collection which is easy to handle by the view (because ObservableCollection<T> implements INotifyCollectionChanged<T>). The type of items in the collection should be a view model (e.g. StockQuoteViewModel) which exposes data from a single StockQuote object. In such a view model you can add logic like adding a $-symbol to Price and so on.

It is often easier to expose some model objects in a view model, but the correct way would be to create a view model for each model class.

Best Regards,
Oliver Hanappi


No. You are not exposing StockQuote. You are only specifying an (loosely typed) interface in the view. The view knows only two properties: Symbol and Price. You can easily replace StockQuote with anything else as long as it implements those.


Check video: Jason Dolinger on MVVM. It will answer your question.

Also, see SO question wpf mvvm confusion for additional resources.


My understanding is that ViewModels are to Models as Properties are to Fields. This is a very loose analogy, but it does imply you're not properly insulated if your View is directly accessing your Model. Just as with trivial properties in a class wrapping private fields, you end up with a lot of duplication and boilerplate code when wrapping relevant Model properties in ViewModel properties for consumption by the View. This is something that bothers me with this pattern and I'm still not decided on whether the benefits are worth the bloat.

In this particular example, I think it would be overkill to create a VM for each StockQuote instance, as you're likely not doing any significant logic for the View that represents an individual StockQuote. I think it's much cleaner and more maintainable in these small cases to simply bind to the Model class directly. Creating a VM for the small case would reduce coupling, but it would also increase complexity and I think it's a case-by-case judgment call as to whether this is beneficial.


Maybe I have this wrong but isn't the idea of the viewmodel to encapsulate the model completely. For instance you have stock quotes exposed to the view but they should be mapped to properties native to the viewmodel which would then be binded to. This is to necessitate "cleaning" that might be needed during the transfer of data to the model/view.

That way the view only ever knows the viewmodel. It also means that if the model was not legacy it could be implemented as an interface and further reduce the coupling between the viewmodel.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号