Silverlight MVVM 模式下与子窗体交互

来源:转载

Model View ViewModel(MVVM)是在 Silverlight 和 WPF 项目开发中应用最多的结构模式,也是 Silverlight 和 WPF 项目开发的最佳模式。本文的主要目的不是讲解 MVVM 模式,如果您不了解 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 中弹出一个子窗体。关于 MvvmLight 的下载及安装请看这里。

首先我们来看一下示例程序的运行结果:

 

程序运行后当用户单击 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  
02 {  

03     private string customerId;  

04     public string CustomerId  

05     {  

06         get { return customerId; }  

07         set 

08         {  

09             customerId = value;  

10             NotifyPropertyChanged("CustomerID");  

11         }  

12     }  

13    

14     private string customerName;  

15     public string CustomerName  

16     {  

17         get { return customerName; }  

18         set 

19         {  

20             customerName = value;  

21             NotifyPropertyChanged("CustomerName");  

22         }  

23     }  

24    

25     private string city;  

26     public string City  

27     {  

28         get { return city; }  

29         set 

30         {  

31             city = value;  

32             NotifyPropertyChanged("City");  

33         }  

34     }  

35    

36     public event PropertyChangedEventHandler PropertyChanged;  

37    

38     public void NotifyPropertyChanged(string propertyName)  

39     {  

40         if (PropertyChanged != null)  

41             PropertyChanged(this, new PropertyChangedEventArgs(propertyName));  

42     }  

43 } 

 

下面是 MainPage 的后置代码:

01 public partial class MainPage : UserControl  

02 {  

03     public MainPage()  

04     {  

05         InitializeComponent();  

06    

07         Messenger.Default.Register<string>(  

08             this,  

09             "MainWindow",  

10             msg =>  

11             {  

12                 NewCustomerView newCustomer = new NewCustomerView();  

13                 newCustomer.Title = msg;  

14                 newCustomer.Show();  

15             });  

16     }  

17 } 

 

从上面的代码中可以看到,我使用 MvvmLight 的 Messenger 在主窗体中注册了一个消息接收者,用于接收 ViewModel 发来的消息并弹出子窗体。下面是子窗体 NewCustomerView 的后置代码:

01 public partial class NewCustomerView : ChildWindow  

02 {  

03     public NewCustomerView()  

04     {  

05         InitializeComponent();  

06    

07         Messenger.Default.Register<Customer>(  

08             this,  

09             "ChildWindow",  

10             msg =>  

11             {  

12                 this.DialogResult = true;  

13             });  

14     }  

15 } 

 

我同样在子窗体中也注册一个消息接收者,接收 ViewModel 发来的消息并关闭子窗体。注意主窗体中注册的消息接收者的 Token 为 “MainWindow”,子窗体中注册的消息接收者的 Token 为 “ChildWindow”,在 ViewModel 中发送消息时,只有与发送的消息的 Token 相同的接收者才收到消息。下面是 MainViewModel 的代码,这里只是为了演示,主窗体和子窗体共用了一个 ViewModel。

01 public class MainViewModel : ViewModelBase  

02 {          

03     public MainViewModel()  

04     {  

05         OKButtonCommand = new RelayCommand<Customer>(OKButtonClick);  

06         NewCustomerCommand = new RelayCommand(NewCustomer);  

07    

08         _customer = new Customer();  

09         _customers = new ObservableCollection<Customer>();  

10         // 注册一个接收者 Token 为 ChildWindow  

11         Messenger.Default.Register<Customer>(this, "ChildWindow", AddCustomer);  

12     }  

13    

14     private void AddCustomer(Customer param)  

15     {  

16         _customers.Add(param);  

17         RaisePropertyChanged("Customers");  

18     }  

19    

20     // customer list  

21     private ObservableCollection<Customer> _customers;  

22     public ObservableCollection<Customer> Customers  

23     {  

24         get 

25         {  

26             return _customers;  

27         }  

28     }  

29    

30     // customer model  

31     private Customer _customer;  

32     public Customer Model  

33     {  

34         get 

35         {  

36             return _customer;  

37         }  

38         set 

39         {  

40             _customer = value;  

41             RaisePropertyChanged("Model");  

42         }  

43     }  

44    

45     // add customer command  

46     public RelayCommand NewCustomerCommand { get; private set; }  

47     private void NewCustomer()  

48     {  

49         /*  

50             * 发送一个字符串信息 New Customer  

51             * Token 为 MainWindow 只有具有相同 Token 接收者都会接收到该信息  

52             */ 

53         Messenger.Default.Send("New Customer", "MainWindow");  

54     }  

55    

56     public RelayCommand<Customer> OKButtonCommand { get; private set; }  

57     private void OKButtonClick(Customer param)  

58     {  

59         /*  

60             * 发送一个 Customer 信息  

61             * Token 为 ChildWindow 只有具有相同 Token 接收者都会接收到该信息  

62             */ 

63         Messenger.Default.Send<Customer>(param, "ChildWindow");  

64     }  

65 } 

 

在 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}" />  

05         </i:EventTrigger>  

06     </i:Interaction.Triggers>  

07 </Button>  

08    

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

13         </i:EventTrigger>  

14     </i:Interaction.Triggers>  

15 </Button> 

本示例只是提供一个在 MVVM 模式下与子窗体交互的解决方法,这个解决方法也并不是纯粹的 MVVM,完整的示例请查看附件的示例代码。

示例代码下载:SLMvvmChildWindow

本文来自forgetu的博客,原文地址:http://www.cnblogs.com/forgetu/archive/2011/06/30/silverlight-mvvm-childwindow-interaction.html


分享给朋友:
您可能感兴趣的文章:
随机阅读: