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@fc6vip.cn
文章轉載自:博客園