前言
由於在實際項目中,業務功能的增加導致軟件開發規模在逐漸變大,所以我准備找個Silverlight框架來組織當前項目中的文件,以期能夠讓后續的業務功能增添和維護更加容易一些。無意中,我在這篇文章中看到了當前Silverlight下所有的框架的評測:Discover and compare existing MVVM frameworks !,當我看到MvvmLight toolkit在各方面都比較完備的時候,於是決定選擇這個框架:
在Codeplex網站上,下載了MVVM Light Toolkit V4 RTM這個版本,因為我用的是vs2010,所以我下載了支持當前機器IDE的版本。
新建項目,選擇MvvmLight(SL4),之后我們就可以看到項目結構了:
其中:
Design文件夾中的文件主要提供設計時運行支持
Model文件夾則放置了富實體模型
Skins文件夾則放置了樣式文件定義
ViewModel文件夾則放置了ViewModel對象,其實MainViewModel和MainPage是一對一的(ViewMoel-View)關系.二者的映射通過ViewModelLocator進行。
MainPage.xaml就是我們的視圖頁面
下面我們就以例子來演示MvvmLight Toolkit中是如何實現MVVM模式,如何綁定命令,如何進行事件消息傳遞的。
首先,在這個框架中,MVVM模式的入口點為ViewModelLocator類,在這個類中,可以定義多個ViewModel屬性,並且每個屬性都可以通過ServiceLocator.Current.GetInstance方法進行映射,以便於暴露給前台綁定。同時,在新增一個ViewModel類的時候,一定要在其提供的SimpleIoc對象容器中進行注冊,以便於能夠通過IOC的方式獲取其實例。
做完映射后,就是我們的ViewModel對象了。它需要繼承自ViewModelBase類,這個類封裝了ICommand,INotifypropertyChanged等接口,使用起來很方便。比如可以用RaisePropertyChanged直接來拋出變更通知。
之后就是View了,在View中,我們需要先對DataContext進行綁定:
DataContext="{Binding Main, Source={StaticResource Locator}}"
然后就可以隨心所欲的操作了。
然后,我們來講解下綁定命令。
由於命令綁定是應用程序中必不可少的環節,所以這里我以 綁定無參事件,綁定一個參數事件,綁定多個參數事件來說明。
綁定無參事件:
#region Command without parameters
private RelayCommand showText;
public RelayCommand ShowText
{
get
{
if (showText == null)
showText = new RelayCommand(ShowTextFunc);
return showText;
}
}
public RelayCommand PassEvent { get; set; }
private void ShowTextFunc()
{
MessageBox.Show("I am RealyCommand!");
}
#endregion
上面代碼就是綁定無參事件,在View上可以通過如下方式綁定:
<Button Content="綁定無參事件"
Command="{Binding ShowText}"
Height="23"
HorizontalAlignment="Left"
Margin="32,62,0,0"
Name="button1"
VerticalAlignment="Top"
Width="141" />
綁定一個參數事件:
#region Command with a parameter
private RelayCommand<int> showValue;
public RelayCommand<int> ShowValue
{
get
{
if (showValue == null)
showValue = new RelayCommand<int>(x=>ShowValueFunc(x));
return showValue;
}
}
private int ShowValueFunc(int a)
{
int c = a + 10;
MessageBox.Show(c.ToString());
return c;
}
#endregion
上面的代碼部分就是綁定一個參數的事件定義,我們來驅動view層:
<Button Content="綁定一個參數事件"
Command="{Binding ShowValue}"
CommandParameter="{Binding ElementName=textBox1,Path=Text,Converter={StaticResource IntConverter}}"
Height="23"
HorizontalAlignment="Left"
Margin="32,103,0,0"
Name="button2"
VerticalAlignment="Top"
Width="141" />
需要說明的是,上面代碼示例中,CommandParameter的值來自於textBox1的Text屬性中。這個值加上10以后返回。
如果遇到用戶輸入不是數字的情況,則通過IntConverter方法將用戶輸入格式化,然后返回:
public class IntConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int result;
if(Int32.TryParse(value.ToString(),out result))
{
return result;
}
return "0";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
綁定多個參數事件:
由於RelayCommand默認最多允許一個參數傳遞,所以這里如果想傳遞多個數據對象,只能夠去構建自己的DTO了。
在Model文件夾新建一個BookItem類:
public class BookItem
{
public string BName { get; set; }
public string BAuthor { get; set; }
}
然后在ViewModel中進行如下控制:
#region Command with multiple parameters
private RelayCommand<BookItem> showBooks;
public RelayCommand<BookItem> ShowBooks
{
get
{
if (showBooks == null)
showBooks = new RelayCommand<BookItem>(x=>ShowBooksFunc(x));
return showBooks;
}
}
private void ShowBooksFunc(BookItem bookItem)
{
MessageBox.Show(bookItem.BName+"|"+bookItem.BAuthor);
}
#endregion
驅動View層:
<Button Command="{Binding ShowBooks}"
Content="綁定多個參數事件"
Height="23"
HorizontalAlignment="Left"
Margin="32,141,0,0"
Name="button3"
VerticalAlignment="Top"
Width="141" >
<Button.CommandParameter>
<model:BookItem BName="testName" BAuthor="TestAuthor" ></model:BookItem>
</Button.CommandParameter>
</Button>
運行起來得時候,我們發現BookItem參數已經被自動賦值了。
ViewModel之間事件傳遞
最后需要講解的是如何在ViewModel之間進行事件傳遞。由於在MVVMLight Toolkit中已經集成了Messenger對象,所以我們可以利用其很方便的進行事件傳遞,下面新建一個ChildWindow1.xaml子窗體,然后在ViewModelLocator中添加如下代碼:
public ChildViewModel Child
{
get
{
return ServiceLocator.Current.GetInstance<ChildViewModel>();
}
}
SimpleIoc.Default.Register<ChildViewModel>();
然后在ViewModel文件夾中新建一個ChildViewModel類,在其中添加如下代碼:
public class ChildViewModel:ViewModelBase
{
public ChildViewModel()
{
Messenger.Default.Register<BookItem>(this, message =>
{
MyText = message.BName + "|" + message.BAuthor;
});
}
public string MyText { get; set; }
}
由於我們傳遞的對象是從 MainViewModel到ChildViewModel,所以我們在MainViewModel中添加如下發送代碼:
#region Messenger communication cross page
private RelayCommand showChildWindow;
public RelayCommand ShowChildWindow
{
get
{
if (showChildWindow == null)
showChildWindow = new RelayCommand(ShowChildWindowFunc);
return showChildWindow;
}
}
private void ShowChildWindowFunc()
{
ChildWindow1 child = new ChildWindow1();
child.Show();
var bookItem = new BookItem() { BAuthor="TestAuthor",BName="TestName" };
Messenger.Default.Send<BookItem>(bookItem);
}
#endregion
這樣當運行起來的時候,我們就能看到效果了:
好了,暫時就到這里,后面我們再深入挖掘。



