胖模型,瘦的ViewModels和愚蠢的视图,最好的MVVM方法? [英] Fat Models, skinny ViewModels and dumb Views, the best MVVM approach?

查看:145
本文介绍了胖模型,瘦的ViewModels和愚蠢的视图,最好的MVVM方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通过对此问题的慷慨帮助,我将以下MVVM结构放在一起,以实时显示模型的更改XAML(当前日期/时间),非常好。

Through generous help on this question, I put together the following MVVM structure which displays the changes of a model in real time in XAML (current date/time), very nice.


这个设置的一个很好的优势是
,当你看您的视图在
设计模式的Visual Studio或
混合,您看到时间滴答作品,
这意味着在设计时,您可以从
模型访问实时数据。

A cool advantage of this set up is that when you look at your view in design mode of Visual Studio or Blend, you see the time ticking by, which means that at design time you have access to live data from your model.

在让这个工作的过程,我很惊讶地看到,从我的ViewModel到我的Model 的大部分批量移动,包括INotifyPropertyChange的实现。另一个变化是,我不再绑定到ViewModel上的属性,而是方法

In the process of getting this to work, I was surprised to see most of the bulk move from my ViewModel into my Model, including implementation of INotifyPropertyChange. Another change is that I no longer bind to properties on the ViewModel but to methods.

所以目前这是我最喜欢的MVVM风格:

So currently this is my favorite flavor of MVVM:


  1. 查看是愚蠢的:

  1. View is dumb:


  • 一个ObjectDataProvider为您的模型需要的每个对象

  • 每个ObjectDataProvider映射对于ViewModel(而不是属性)的方法

  • 否x:XAML元素中的名称属性

ViewModel是瘦的:

ViewModel is skinny:


  • 您的ViewModel中唯一的东西是方法您的视图绑定

  • the only thing in your ViewModel are the methods to which your view binds

模型很胖:


  • 该模型在其每个属性上实现INotifyPropertyChanged。

  • 对于ViewModel上的每个方法(例如GetCurrentCustomer),都有一个相应的单例方法您的模型(例如GetCurrentCustomer)。

  • 该模型负责处理任何实时线程功能,如本示例

  • the model implements INotifyPropertyChanged on each of its properties.
  • for every method on your ViewModel (e.g. GetCurrentCustomer) there is a corresponding singleton method in your Model (e.g. GetCurrentCustomer).
  • the model takes care of any real time threading functionality as in this example

问题:


  1. 那些在实际情况下实现MVVM的人,这是您已经解决的基本结构,如果没有,您的方式如何变化?

  2. 你将如何将其扩展为包括路由命令和路由事件?

如果您将XAML和代码复制到新的WPF项目中,以下代码将会起作用。

XAML: / p>

XAML:

<Window x:Class="TestBinding99382.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestBinding99382"
    Title="Window1" Height="300" Width="300">

    <Window.Resources>
        <ObjectDataProvider 
             x:Key="DataSourceCustomer" 
             ObjectType="{x:Type local:ShowCustomerViewModel}" 
                        MethodName="GetCurrentCustomer"/>
    </Window.Resources>

    <DockPanel DataContext="{StaticResource DataSourceCustomer}">
        <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
            <TextBlock Text="{Binding Path=FirstName}"/>
            <TextBlock Text=" "/>
            <TextBlock Text="{Binding Path=LastName}"/>
        </StackPanel>
        <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
            <TextBlock Text="{Binding Path=TimeOfMostRecentActivity}"/>
        </StackPanel>

    </DockPanel>
</Window>

代码背后:

using System.Windows;
using System.ComponentModel;
using System;
using System.Threading;

namespace TestBinding99382
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }
    }

    //view model
    public class ShowCustomerViewModel
    {
        public Customer GetCurrentCustomer() {
            return Customer.GetCurrentCustomer();
        }
    }

    //model
    public class Customer : INotifyPropertyChanged
    {
        private string _firstName;
        private string _lastName;
        private DateTime _timeOfMostRecentActivity;
        private static Customer _currentCustomer;
        private Timer _timer;

        public string FirstName
        {
            get
            {
                return _firstName;
            }
            set
            {
                _firstName = value;
                this.RaisePropertyChanged("FirstName");
            }
        }

        public string LastName
        {
            get
            {
                return _lastName;
            }
            set
            {
                _lastName = value;
                this.RaisePropertyChanged("LastName");
            }
        }

        public DateTime TimeOfMostRecentActivity
        {
            get
            {
                return _timeOfMostRecentActivity;
            }
            set
            {
                _timeOfMostRecentActivity = value;
                this.RaisePropertyChanged("TimeOfMostRecentActivity");
            }
        }

        public Customer()
        {
            _timer = new Timer(UpdateDateTime, null, 0, 1000);
        }

        private void UpdateDateTime(object state)
        {
            TimeOfMostRecentActivity = DateTime.Now;
        }

        public static Customer GetCurrentCustomer()
        {
            if (_currentCustomer == null)
            {
                _currentCustomer = new Customer 
                     {  FirstName = "Jim"
                        , LastName = "Smith"
                        , TimeOfMostRecentActivity = DateTime.Now 
                     };
            }
            return _currentCustomer;
        }

        //INotifyPropertyChanged implementation
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
    }
}


推荐答案

这是我的意见,为什么值得:

Here's my opinion, for what it's worth :

我不太同意你建议的方法(除了愚蠢的观点)。在现实生活中,您通常必须使用现有的模型:它可能是您没有时间(或将要更改)的遗留代码,甚至是您没有代码的库。在我看来,该模型应该完全不知道它将被显示的方式,并且应该在非WPF应用程序中很容易使用。因此,它不需要实现任何特定的界面,如 INotifyPropertyChanged INotifyCollectionChanged ,使其在MVVM中可用。我认为所有与UI相关的逻辑应该存在于ViewModel中。

I don't really agree with the approach you suggest (except for the dumb view). In real life, you will often have to use an existing model : it could be legacy code that you don't have the time (or will) to change, or even a library for which you don't have the code. In my opinion, the model should be completely unaware of the way it will be displayed, and should be easily usable in a non-WPF application. So it doesn't have to implement any specific interface like INotifyPropertyChanged of INotifyCollectionChanged to make it usable in MVVM. I think that all the logic related to UI should reside in the ViewModel.

关于 RoutedEvents RoutedCommands ,它们并不适合用于MVVM模式。我通常尽量使用尽可能少的 RoutedEvents ,而根本没有 RoutedCommands 。相反,我的ViewModels公开了我绑定到XAML中的UI的 RelayCommand 属性(请参阅 RelayCommand )的详细信息,由Josh Smith发表/dd419663.aspxrel =noreferrer>这篇文章。当我真的需要处理某些控件的事件时,我使用附加的行为将事件映射到ViewModel命令(看一下 Marlon Grech的实现

Regarding RoutedEvents and RoutedCommands, they are not really suitable for use with the MVVM pattern. I usually try to use as little RoutedEvents as possible, and no RoutedCommands at all. Instead, my ViewModels expose RelayCommand properties that I bind to the UI in XAML (see this article by Josh Smith for details on RelayCommand). When I really need to handle events for some control, I use attached behaviors to map the events to ViewModel commands (have a look at Marlon Grech's implementation)

总之:


  • Dumb View

  • 大而聪明的ViewModel

  • 您想要或必须使用的任何型号

当然这只是我的方法,它可能不是最好的,但我觉得很舒服;)

Of course it's just my approach, and it may not be the best, but I feel quite comfortable with it ;)

这篇关于胖模型,瘦的ViewModels和愚蠢的视图,最好的MVVM方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆