本篇是MvvmLight框架使用入門的第三篇。從本篇開始,所有代碼將通過Windows 10的Universal App來演示。我們將創建一個Universal App並應用MvvmLight框架。
首先通過VS2015創建一個名爲UniversalApp的空工程(工程類型爲Universal Windows),然後通過NuGet獲取MvvmLight,這裏需要注意的是,我們選擇MvvmLightLib僅下載DLL文件,因爲MvvmLight還未對Universal App做適配,並不會自動創建ViewModel以及ViewModelLocator等文件。
在創建UniversalApp完成後,將上一篇創建的HelloMvvmLight工程中的ViewModel文件夾整個拷貝到UWP工程裏(注意修改namespace)。這樣MainViewModel以及ViewModelLocator文件就有了。
接着在App.xaml的Resources中添加對ViewModelLocator的引用:
<Application.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator" />
</ResourceDictionary>
</Application.Resources>
這裏需要注意保持namespace和ViewModel的namespace一致:xmlns:vm=”using:UniversalApp.ViewModel”
再下一步就是修改MainPage.xaml文件,將xaml的內容修改如下:
<Page.DataContext>
<Binding Path="Main" Source="{StaticResource Locator}"/>
</Page.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Text="{Binding Title}"></TextBlock>
<Button Grid.Row="1" Command="{Binding ChangeTitleCommand}">Click Me!</Button>
</Grid>
至此,一個簡單的使用了MvvmLight框架的Uinversal App就完成了。
按下Ctrl+F5,一個Win10風格的窗體就出現了。(細心的童鞋會發現Button默認不再撐開了),當然本篇不會只有這點東西,我們會進一步介紹MvvmLight框架在Universal App下的使用。
接下來我們增加第二個頁面,來看一下MvvmLight對頁面間導航的支持。
第一步新建PageTwoViewModel類:
public class PageTwoViewModel
{
private INavigationService _navigationService;
public ICommand GoBackCommand { get; set; }
public PageTwoViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
GoBackCommand = new RelayCommand(()=> { _navigationService.GoBack(); });
}
}
INavigationService是MvvmLight爲了抽象各類型的工程(WPF,Silverlight,Windows Runtime)不同的導航方法,而設計的接口,定義如下:
public interface INavigationService
{
string CurrentPageKey { get; }
void GoBack();
void NavigateTo(string pageKey);
void NavigateTo(string pageKey, object parameter);
}
通過string字符串確認唯一頁面來進行跳轉和返回,並可以傳遞object類型的參數。
ViewModelLocator類註冊PageTwoViewModel,以及創建INavigationService的實例並關聯各Page。
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<PageTwoViewModel>();
var navigationService = this.CreateNavigationService();
SimpleIoc.Default.Register<INavigationService>(() => navigationService);
}
private INavigationService CreateNavigationService()
{
var navigationService = new NavigationService();
navigationService.Configure("MainPage", typeof(MainPage));
navigationService.Configure("PageTwo", typeof(PageTwo));
return navigationService;
}
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
public PageTwoViewModel PageTwo
{
get
{
return ServiceLocator.Current.GetInstance<PageTwoViewModel>();
}
}
至於爲什麼只要在PageTwoViewModel的構造函數參數中帶有INavigationService,即可由IOC自動獲取實例navigationService則超出了本文討論的範圍,有興趣的同學自行學習。
構建PageTwo.xaml頁面並關聯至PageTwoViewModel。
<Page.DataContext>
<Binding Path="PageTwo" Source="{StaticResource Locator}"/> </Page.DataContext>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Text="Page Two"></TextBlock>
<Button Grid.Row="1" Command="{Binding GoBackCommand}">Go Back</Button>
</Grid>
</Grid>
修改MainViewModel類,增加GotoNextCommand等方法。同時我們可以看到手動獲取navigationService對象的方法。
public class MainViewModel : ViewModelBase
{
private string title;
public string Title
{
get { return title; }
set { Set(ref title , value); }
}
public ICommand ChangeTitleCommand { get; set; }
public ICommand GotoNextCommand { get; set; }
public MainViewModel()
{
Title = "Hello World";
ChangeTitleCommand = new RelayCommand(ChangeTitle);
GotoNextCommand = new RelayCommand(GotoNext);
}
private void GotoNext()
{
var navigationService = ServiceLocator.Current.GetInstance<INavigationService>();
navigationService.NavigateTo("PageTwo");
}
private void ChangeTitle()
{
Title = "Hello MvvmLight";
}
}
MainPage.xaml僅僅是增加了一個GotoNext的Button:
<Button Grid.Row="2" Command="{Binding GotoNextCommand}">Go to Next!</Button>
大功告成,按下Ctrl+F5試試吧。
- 使用MvvmLight框架中的INavigationService來進行頁面導航,雖然相對使用Frame導航稍稍增加了工作量,但具有以下幾點好處:
- 不依賴具體的工程實現(WPF,Sliverlight,Windows Runtime)。
- View和ViewModel不直接產生依賴,雙方通過中介INavigationService打交道。也就是說ViewModel中不會出現Windows.UI.Xaml.Controls的namespace。
- 將跳轉的實現代碼從View轉移到ViewModel,使得單元測試可以脫離View,完全的通過ViewModel的UT即可測試跳轉的邏輯。