Model View ViewModel(MVVM)是在 Silverlight 和 WPF 项目开发中应用最多的结构模式,也是 Silverlight 和 WPF 项目开发的最佳模式。本文的主要目的不是讲解 MVVM 模式。目前已有很多 MVVM 框架可以用来简化 MVVM 开发,如 Prism、SilverlightFX、MvvmLight、Caliburn、Simple MVVM Toolkit等。
  在  程序开发中经常会遇到诸如弹出提示框、确认框、用户输入窗口等的情况,在 Silverlight 中这些情况都可以用子窗体(Child   Window)来处理。在未使用 MVVM 模式的情况下,我们可以在用户控件或页面的后置代码(Code   Behind)中实例化一个子窗体,调用子窗体的 Show 方法来弹出子窗体,然后通过子窗体的 Closed 方法用户的操作结果。但是在使用   MVVM 模式的情况下,为了使 Model 和 View   最大限度的分离,我们要使用尽可能少的后置代码。如果在后置代码中实例化并显示子窗体,这就使用代码和视图结合在一起了;当然也可以在   ViewModel 里实例化并显示子窗体,这样又使子窗体和 ViewModel 结合在一起了。
  本文将使用 MvvmLight 框架来演示如何在 MVVM 模式下与子窗体交互,即如何在 ViewModel 中弹出一个子窗体。
  首先我们来看一下示例程序的运行结果:
 
 
  程序运行后当用户单击 New Customer 按钮时,就会弹出一个子窗体,用户输入Customer Id、Customer Name、Customer City 后单击 OK 按钮就会在主页面的客户列表中显示出刚才输入的客户信息。下面是本示例具体的实现。
  新  建一个 Silverlight 项目,然后在项目中添加Views、Models、ViewModels、Locators文件夹(如果是通过   MvvmLight 模板创建的 Silverlight 项目,默认 ViewModel Locator 和 ViewModel   在同一文件夹中)。添加对程序集 GalaSoft.MvvmLight.Extras.SL4 和 GalaSoft.MvvmLight.SL4   的引用(如果通过 MvvLight 模板创建则会自动引用)。在 Model 文件夹中新建一个 Customer Model,完整代码如下:
    
        
            | 01 | public class Customer : INotifyPropertyChanged | 
    
 
    
        
            | 03 | private string customerId; | 
    
 
    
        
            | 04 | public string CustomerId | 
    
 
    
        
            | 06 | get { return customerId; } | 
    
 
    
        
            | 10 | NotifyPropertyChanged("CustomerID"); | 
    
 
    
        
            | 14 | private string customerName; | 
    
 
    
        
            | 15 | public string CustomerName | 
    
 
    
        
            | 17 | get { return customerName; } | 
    
 
    
        
            | 21 | NotifyPropertyChanged("CustomerName"); | 
    
 
    
        
            | 32 | NotifyPropertyChanged("City"); | 
    
 
    
        
            | 36 | public event PropertyChangedEventHandler PropertyChanged; | 
    
 
    
        
            | 38 | public void NotifyPropertyChanged(string propertyName) | 
    
 
    
        
            | 40 | if (PropertyChanged != null) | 
    
 
    
        
            | 41 | PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); | 
    
 
 
 
  下面是 MainPage 的后置代码:
    
        
            | 01 | public partial class MainPage : UserControl | 
    
 
    
        
            | 05 | InitializeComponent(); | 
    
 
    
        
            | 07 | Messenger.Default.Register<string>( | 
    
 
    
        
            | 12 | NewCustomerView newCustomer = new NewCustomerView(); | 
    
 
    
        
            | 13 | newCustomer.Title = msg; | 
    
 
 
 
  从上面的代码中可以看到,我使用 MvvmLight 的 Messenger 在主窗体中注册了一个消息接收者,用于接收 ViewModel 发来的消息并弹出子窗体。下面是子窗体 NewCustomerView 的后置代码:
    
        
            | 01 | public partial class NewCustomerView : ChildWindow | 
    
 
    
        
            | 03 | public NewCustomerView() | 
    
 
    
        
            | 05 | InitializeComponent(); | 
    
 
    
        
            | 07 | Messenger.Default.Register<Customer>( | 
    
 
    
        
            | 12 | this.DialogResult = true; | 
    
 
 
 
  我同样在子窗体中也注册一个消息接收者,接收 ViewModel 发来的消息并关闭子窗体。注意主窗体中注册的消息接收者的 Token 为   “MainWindow”,子窗体中注册的消息接收者的 Token 为 “ChildWindow”,在 ViewModel   中发送消息时,只有与发送的消息的 Token 相同的接收者才收到消息。下面是 MainViewModel   的代码,这里只是为了演示,主窗体和子窗体共用了一个 ViewModel。
    
        
            | 01 | public class MainViewModel : ViewModelBase | 
    
 
    
        
            | 03 | public MainViewModel() | 
    
 
    
        
            | 05 | OKButtonCommand = new RelayCommand<Customer>(OKButtonClick); | 
    
 
    
        
            | 06 | NewCustomerCommand = new RelayCommand(NewCustomer); | 
    
 
    
        
            | 08 | _customer = new Customer(); | 
    
 
    
        
            | 09 | _customers = new ObservableCollection<Customer>(); | 
    
 
    
        
            | 10 | // 注册一个接收者 Token 为 ChildWindow | 
    
 
    
        
            | 11 | Messenger.Default.Register<Customer>(this, "ChildWindow", AddCustomer); | 
    
 
    
        
            | 14 | private void AddCustomer(Customer param) | 
    
 
    
        
            | 16 | _customers.Add(param); | 
    
 
    
        
            | 17 | RaisePropertyChanged("Customers"); | 
    
 
    
        
            | 21 | private ObservableCollection<Customer> _customers; | 
    
 
    
        
            | 22 | public ObservableCollection<Customer> Customers | 
    
 
    
        
            | 31 | private Customer _customer; | 
    
 
    
        
            | 41 | RaisePropertyChanged("Model"); | 
    
 
    
        
            | 45 | // add customer command | 
    
 
    
        
            | 46 | public RelayCommand NewCustomerCommand { get; private set; } | 
    
 
    
        
            | 47 | private void NewCustomer() | 
    
 
    
        
            | 50 | * 发送一个字符串信息 New Customer | 
    
 
    
        
            | 51 | * Token 为 MainWindow 只有具有相同 Token 接收者都会接收到该信息 | 
    
 
    
        
            | 53 | Messenger.Default.Send("New Customer", "MainWindow"); | 
    
 
    
        
            | 56 | public RelayCommand<Customer> OKButtonCommand { get; private set; } | 
    
 
    
        
            | 57 | private void OKButtonClick(Customer param) | 
    
 
    
        
            | 61 | * Token 为 ChildWindow 只有具有相同 Token 接收者都会接收到该信息 | 
    
 
    
        
            | 63 | Messenger.Default.Send<Customer>(param, "ChildWindow"); | 
    
 
 
 
  在 ViewModel 中也注册了一个消息接收者,用于接收子窗体返回的数据。ViewModel 中的 NewCustomerCommand   是绑定到主窗体的 NewCustomer 按钮的,单击按钮 NewCustomer 时调用 NewCustomer()   方法向主窗体发送一个消息, 主窗体接收到消息后弹出子窗体。ViewModel 中的 OKButtonCommand 是绑定到子窗体的   OKButton 的,单击按钮 OKButton 时调用 OKButtonClick() 向子窗体和 ViewModel   发送一个消息,子窗体接收到消息时关闭,ViewModel 接收到消息时将参数 Customer 添加 Customer   列表中。以下是按钮的事件绑定代码:
    
        
            | 01 | <Button Content="New Customer" Width="120" Height="30"> | 
    
 
    
        
            | 02 | <i:Interaction.Triggers> | 
    
 
    
        
            | 03 | <i:EventTrigger EventName="Click"> | 
    
 
    
        
            | 04 | <cmd:EventToCommand Command="{Binding NewCustomerCommand}" /> | 
    
 
    
        
            | 06 | </i:Interaction.Triggers> | 
    
 
    
        
            | 09 | <Button x:Name="OkButton" Content="OK" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1"> | 
    
 
    
        
            | 10 | <i:Interaction.Triggers> | 
    
 
    
        
            | 11 | <i:EventTrigger EventName="Click"> | 
    
 
    
        
            | 12 | <cmd:EventToCommand Command="{Binding OKButtonCommand}" CommandParameter="{Binding ElementName=Customer, Path=DataContext}" /> | 
    
 
    
        
            | 14 | </i:Interaction.Triggers> | 
    
 
 
 
  本示例只是提供一个在 MVVM 模式下与子窗体交互的解决方法,这个解决方法也并不是纯粹的 MVVM,完整的示例请查看附件的示例代码。
					
					标签:
MVVM
					
					
						本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@ldacury.cn
												文章转载自:博客园