3

Having passed a series of Edward Tanguay's questions refractoring the usage of MVVM for WPF app which can be found in Linked sidebar of his Fat Models, skinny ViewModels and dumb Views, the best MVVM approach?, I am a little confused by his final WPF application in Big smart ViewModels, dumb Views, and any model, the best MVVM approach?

Its M (Model) is Customer class:

//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 
                   };
    }

}

which returns current user. Kind of, beause it returns duplicates of newly created "current" user...

But where is the M's data stored and updated in case of need?

Suppose, I want to change the model's current user's FirstName to "Gennady"?

I added a button for updating the model with this button click event handler:

private void button1_Click(object sender, RoutedEventArgs e)
{


} 

aiming to change the model's data from it which will be reflected in GUI.

How can I do this, by clicking this button... sorry, by placing the code into this button1_Click()?

Or it is something wrong with my wish to do it?
Then. how to correctly update/change M in MVVM ?

Update:
All answers seem refer that I should not make changes in M but on VM.
Though I've specifically asked about referenced M-V-VM implementation with:

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;
}

So, for example, upon implementing the code from Adolfo Perez's answer changes, the TextBox's content is changed from "Jim" to "Gennady" only for a period of interval set in _timer = new Timer(CheckForChangesInModel, null, 0, 1000);.

All logic of referenced by me M-V-VM in WPF approach is such that it is "M" should be updated, in order VM has caught up those changes, but not the "VM".

Even more, I cannot understand, if to make changes in VM how can they be reflected in M if the VM knows about M but - not vice versa - Model does not know about ViewModel).

4

4 回答 4

11

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

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

在您看来:

<Button Content="Change FirstName" 
        Command="{Binding Path=ChangeFirstNameCommand"}/>

在您的视图模型中:

//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了解您的VM,而您的VM了解您的M,但反之则不然。

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

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

    <TextBox Text=
         "{Binding Path=FirstName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
    

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

  • 将您的 View.DataContext 设置为您的VM。这是为所有数据绑定设置上下文的原因,除非您指定不同的绑定源。
  • 如果您想在数据库中持久化更改,请在您的VM中注入一个服务类,该类将负责 CRUD 操作

看看这个简单的例子:

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

于 2013-04-19T09:54:32.240 回答
3

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

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

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

有这样的代码:

private void button1_Click(object sender, RoutedEventArgs e)
{


} 

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

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

于 2013-04-19T09:33:19.533 回答
1

首先,你需要处理你的Vand VM

如果您为按钮使用Click事件,那么您肯定没有遵循此架构。

您需要使用WPFandXAML在您的视图中绑定到您的ViewModel,您ViewModel应该是特定或潜在许多模型的子集,并将属性提供给View允许绑定的 。

我也会考虑研究:

  • RelayCommandICommand用于绑定您的按钮。
  • Repository用于交换模型并创建一种方式的模式CRUD

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

于 2013-04-19T09:28:45.510 回答
0

如果您有一个纯 WPF 应用程序,那么研究 MVVM 的“反向”模式 ViewModel-First 可能会很有趣。

对于 web 开发,通常使用 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();
于 2013-04-26T19:52:06.913 回答