如何(正确)更新WPF应用程序的MVVM中的M?

已经通过了一系列爱德华Tanguay的问题,折射MVF应用程序的MVVM,可以在他的Fat Models的链接侧边栏,瘦瘦的ViewModel和哑视图中找到,这是最好的MVVM方法吗? ,他对Big smart ViewModels中的最终WPF应用程序,哑视图和任何模型,最好的MVVM方法感到有些困惑?

其M(模型)是客户类 :

//model public class Customer { public string FirstName { get; set; } public string LastName { get; set; } public DateTime TimeOfMostRecentActivity { get; set; } public static Customer GetCurrentCustomer() { return new Customer { FirstName = "Jim" , LastName = "Smith" , TimeOfMostRecentActivity = DateTime.Now }; } } 

返回当前用户。 那种,因为它返回了新创建的“当前”用户的重复…

但是,在需要的情况下,M的数据存储和更新在哪里?

假设,我想将模型的当前用户的FirstName更改为“Gennady”?

我添加了一个按钮,用于使用此按钮单击事件处理程序更新模型:

 private void button1_Click(object sender, RoutedEventArgs e) { } 

旨在从中更改模型的数据,这将反映在GUI中。

如何通过单击此按钮来执行此操作…抱歉,将代码放入此按钮button1_Click()

或者我希望这样做有问题吗?
然后。 如何在MVVM中正确更新/更改M?

更新:
所有答案似乎都提到我不应该在M中进行更改,而是在VM上进行更改。
虽然我特别询问了引用的MV-VM实现 :

 public CustomerViewModel() { _timer = new Timer(CheckForChangesInModel, null, 0, 1000); } private void CheckForChangesInModel(object state) { Customer currentCustomer = CustomerViewModel.GetCurrentCustomer(); MapFieldsFromModeltoViewModel(currentCustomer, this); } public static void MapFieldsFromModeltoViewModel (Customer model, CustomerViewModel viewModel) { viewModel.FirstName = model.FirstName; viewModel.LastName = model.LastName; viewModel.TimeOfMostRecentActivity = model.TimeOfMostRecentActivity; } 

因此,例如,在实现Adolfo Perez的答案更改代码时, TextBox的内容仅在“ _timer = new Timer(CheckForChangesInModel, null, 0, 1000);设置的间隔时间内从“Jim”更改为“Gennady” _timer = new Timer(CheckForChangesInModel, null, 0, 1000);

我在WPF方法中引用MV-VM的所有逻辑都应该更新“M” ,以便VM捕获这些更改,而不是“VM”。

甚至更多,我无法理解,如果要在VM中进行更改,如果VM知道M,它们如何反映在M中 – 但反之亦然 – 模型不知道ViewModel)。

在MVVM中,您应该避免代码隐藏。 原因是您希望最终得到可测试的类,在这种情况下,您的VM完全独立于您的V. 您可以在VM上运行一组unit testing,而不涉及V. 您还可以在不影响业务逻辑的情况下挂钩不同类型的视图。

您的按钮将其Command属性绑定到VM中公开的ICommand属性。 VM中的此命令将以您指定的方法处理您的单击事件。

在您的视图中:

  

在您的ViewModel中:

 //Define your command public ICommand ChangeFirstNameCommand {get;set;} //Initialize your command in Constructor perhaps ChangeFirstNameCommand = new RelayCommand(OnChangeFirstName,CanChangeFirstName); private void OnChangeFirstName() { //Your FirstName TextBox in your V will be updated after you click the Button this.FirstName = "Gennady"; } private bool CanChangeFirstName() { //Add any validation to set whether your button is enabled or not. // WPF internals take care of this. return true; } 

请记住,在这种模式中,您的V知道您的虚拟机,而您的虚拟机知道您的M但不是相反的方式,这一点非常重要。

在您的示例中,如果要更改Model FirstName属性,则必须执行以下操作:

  • 创建一个实现INotifyPropertyChangedVM
  • VM中公开您的M FirstName属性通知更改
  • 在XAML视图中创建一个TextBox,并将其Text属性绑定到VM .FirstName设置Binding Mode = TwoWay。

      

当您在TextBox中键入时,您的FirstName将直接填充在VM-M中。 此外,由于双向绑定,如果您在VM中修改FirstName属性,该更改将自动反映在您的V中

  • 将View.DataContext设置为VM 。 这是为所有数据绑定设置Context的原因,除非您指定了不同的绑定源。
  • 如果要在数据库中保留更改,则在VM中注入一个服务类,用于处理CRUD操作

看看这个简单的例子:

http://www.codeproject.com/Articles/126249/MVVM-Pattern-in-WPF-A-Simple-Tutorial-for-Absolute

您的模型是您的域(业务)对象。 你可以通过多种方式获得它们。 例如,您可能有一个存储库类,在您请求数据时为您提供数据,并在您希望存储时处理持久性。

您的视图模型是一个处理UI逻辑的类,如更新字段,对用户操作做出反应等。在您的情况下,您可以将CustomerRepository类的实例传递给视图模型。 然后在视图模型代码中,您从存储库中获取Customer实例,并填充您的UI元素绑定的视图模型属性。

您的视图只是您希望向用户显示信息的一组规则。 它必须尽可能具有声明性和逻辑性。

有这样的代码:

 private void button1_Click(object sender, RoutedEventArgs e) { } 

在你看来(或者更糟糕的是 – 在你的视图模型中)是一个巨大的错误,它打破了模式,可能(并且肯定会)导致麻烦。 您应该将ViewModel的ICommand字段绑定到按钮。 您不应该尝试以WinForm事件驱动的方式编写WPF应用程序。

这就是mvvm的一般工作方式,它的主要目的是在您的应用程序中支持多层体系结构 。

首先,您需要处理VVM

如果您对某个按钮使用Click事件,那么您肯定不会遵循此体系结构。

您需要在视图中使用WPFXAML绑定到ViewModelViewModel应该是特定或可能很多模型的子集,并向View提供允许绑定的属性。

我也会考虑研究:

  • 用于绑定按钮的RelayCommandICommand
  • 用于交换模型和创建CRUD方式的Repository模式

您所遵循的教程似乎并不是很好,因为这些概念没有真正正确地进行过,或者您还没有理解它们。

如果你有一个纯WPF应用程序,调查MVVM’反向’模式,ViewModel-First可能会很有趣。

对于webdevelopment,通常使用MVVM,因为网页是通过浏览器加载的,而View是通过创建ViewModel来构建的。

WPF用户不浏览页面(除非您使用页面导航),因此跟随VM-V-VM-M会更有趣:

 interface IMyView Show(); //view implementations in different assemblies: //silverlight class SilverlightMyView:IMyView Show(); //wpf class WpfMyView:IMyView Show(); class MyViewModel IMyView _view; MyModel _model; //ex. view resolved by DI (Unity, ..) MyViewModel(IMyView view) _view = view Show(model as MyModel) _model = model; _view.DataContext = this; _view.Show();