MVVM Light須要註意的10個問題
MVVM Light須要註意的10個問題
從使用XAML技術基礎開始(實際上並非非常久曾經)。我便關註MVVM(Model – View – ViewModel)模式。
偶然接觸到MVVM Light不久後便喜歡上它的工作方式。不光我包含業余和專業開發者在內的非常多開發者都喜歡這個函數庫。依照開發者意願,MVVM Light 不是一個框架而是函數庫,該函數庫註重於探究建立一個MVVM結構而且提供一些額外的幫助類以便於應用。
MVVM Light在發展過程中改變了非常多,非常多元素被增加又有非常多元素被舍棄。但一直保留了高速、易用的輕量級架構。作者Laurent Bugnion,關註於傾聽MVVM Light用戶的聲音。合並特性請求並幫助開發人員。當和一些跟我一起的開發人員聊天的時候,我數次發現某些MVVM Light中的元素他們都沒聽說過在其他地方也是如此。
我跟用戶討論的時候也學到了非常多MVVM Light的新東西。
回想一番後便有了寫博客的想法,並以經常使用的“10個關於……”作為標題,這裏會告你比較easy忽視的10個MVVM Light隱藏的寶玉。
1、 MVVM Light 安裝
這個問題比較顯而易見。可是在通過NuGet安裝會失去一些長處,MVVM的MSI安裝方式不僅給你安裝上二進制文件。同一時候也能在VS中提供project、項目模板和非常多snippets。萬一VS2012更新2刪除了你的模板,能夠從C:\Program Files (x86)\Laurent Bugnion (GalaSoft)\Mvvm Light Toolkit\Vsix中又一次安裝VSIX,這樣就能在VS中獲取project模板。
2、 構造器註入
該功能很強大。實際上是多數依賴註入(DI)架構的特性。MVVM Light在應用程序開啟後(應用程序生命周期內)使用SimpleIoc註冊viewmodel和service類。
構造器註入是指在類的構造函數中能夠指定參數。當該類被實例化,SimpleIoc就試探查找同樣類型的註冊類作為參數。假設能查找到,這個實例就作為構造函數的參數被註入。
以下這個樣例,演示在ViewModelLocator中註冊navigation service.
Code Snippet
SimpleIoc.Default.Register<INavigationService, NavigationService
我們打算在控制反轉(IOC)容器中註冊INavigationService。當它創建實例,我們希望它的類型是NavigationService。眼下IOC 容器中該“記錄”並沒有實例。當首次從容器中獲取時才幹被實例化。有時候當你註冊後立刻想創建實例,SimpleIoc重載函數Register<T>就可以實現該功能。
Code Snippet
1. SimpleIoc.Default.Register<INavigationService, NavigationService>(true);
只將參數輸入為true就能立刻創建實例。如今。我們打算在MainViewModel中使用NavigationService。
Code Snippet
1. ///<summary>
2. /// Initializes a new instance of the MainViewModel class.
3. ///</summary>
4. public MainViewModel(INavigationService navigationService)
5. {
6.
7. }
SimpleIoc 會查找註冊的INavigationService 類型而且在構造函數中註入它。這節省了我們手工接觸IOC容器和索取正確實例的麻煩。
警告:要註意。在IOC容器中註冊類的順序很重要。特別是使用重載函數創建實例時。假設在NavigationService 被註冊之前創建MainViewModel ,那就會得到空引用的異常。
3. 替代SimpleIoc
SimpleIoc庫執行的非常棒。是一個非常酷的輕量級的MVVM Light加入物,並且它的確非常輕量級。它是非常有用的方案可是對於比較大的應用就不那麽好用了(或者你像我一樣打算試一下替代它有多困難)。在這個樣例中我會用AutoFac替代SimpleIoc。AutoFac是一個非常有名且強大的IOC service。
首先,我們要獲取AutoFac庫和extra庫以像SimpleIoc一樣使用ServiceLocator。因此不論從控制臺還是用戶界面為AutoFac加入CommonServiceLocator extra,AutoFac庫是被依賴庫因此要安裝正確。
使用全新的Windows Phone8項目開始MVVM Light項目模板。
Code Snippet
1. Install-Package Autofac.Extras.CommonServiceLocator
只須要被改動代碼的一個地方在ViewModeeLocator。
在這個新的ViewModelLocator構造函數中,我凝視了原先SimpleIoc代碼方便於兩者對照。
Code Snippet
1. static ViewModelLocator()
2. {
3. var container = newContainerBuilder();
4.
5. //ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
6. ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(container.Build()));
7.
8. if (ViewModelBase.IsInDesignModeStatic)
9. {
10. //SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
11. container.RegisterType<Design.DesignDataService>().As<IDataService>();
12. }
13. else
14. {
15. //SimpleIoc.Default.Register<IDataService, DataService>();
16. container.RegisterType<DataService>().As<IDataService>();
17. }
18.
19. //SimpleIoc.Default.Register<MainViewModel>();
20. container.RegisterType<MainViewModel>();
21. }
我們聲明了ContainerBuilder,把它設置為LocatorProvider。
如今容器被用於註冊我們須要的全部東西。通過註冊創建實例的SimpleIoc重載。在AutoFac中呈現例如以下。
Code Snippet
1. container.RegisterInstance(newDataService()).As<IDataService>();
就這樣,構造器註入可以像原來的SimpleIoc正確執行。
4. Built-in messages
MVVM Light的messager能將類註冊為Listeners而且可以將消息發送給這些類。
這通常應用在viewmodel之間,一般我會創建各種類型的消息來發送,可是MVVM Light本身創建了非常多messages供我們調用。
消息GenericMessage<T>(T content)能包括全部的類型。
Code Snippet
1. Messenger.Default.Send(newGenericMessage<string>("my message"));
消息NotificationMessage(string notification)包括notification,能被用於發送notification給notification工廠用以用合適的方式顯示消息。
Code Snippet
1. try
2. {
3. //try something
4. }
5. catch (Exception ex)
6. {
7. Messenger.Default.Send(newNotificationMessage(ex.Message));
8. }
NotificationMessage<T>(T notification)可能相同是你須要的。
另外一個是 NotificationMessageAction(string notification, Action callback) 基於 NotificationMessage 可是你能加入回調行為,該行為會在消息被接收時啟動。它也有類似於implementation的一般實現。
DialogMessage(string content, Action<MessageBoxResult> callback) 這個消息是讓用戶輸入並在參數MessageBoxResult中返回結果。
MessageBoxResult是System.Windows中的枚舉。
Code Snippet
1. publicenumMessageBoxResult
2. {
3. None = 0,
4. OK = 1,
5. Cancel = 2,
6. Yes = 6,
7. No = 7,
8. }
Code Snippet
1. Messenger.Default.Send(newDialogMessage("Are you sure?
", result =>
2. {
3. if (result == MessageBoxResult.Yes)
4. {
5. //do something
6. }
7. }));
DialogMessage 繼承於GenericMessage<string>。
PropertyChangedMessage 是使用在RaisePropertyChanged 的實現,多用於多個viewmodel須要響應屬性變化時。
Code Snippet
1. publicstring WelcomeTitle
2. {
3. get
4. {
5. return _welcomeTitle;
6. }
7.
8. set
9. {
10. if (_welcomeTitle == value)
11. {
12. return;
13. }
14.
15. Messenger.Default.Send(newPropertyChangedMessage<string>(_welcomeTitle, value, "WelcomeTitle"));
16.
17. _welcomeTitle = value;
18. RaisePropertyChanged(WelcomeTitlePropertyName);
19. }
20. }
特別註意註冊監聽者,嘗試使用盡可能多的不同消息類型是有意義的。你並不想讓一個錯誤的監聽者收到消息由於它可能恰好聽到同樣的信息。例如以下所看到的註冊監聽者。
Code Snippet
1. Messenger.Default.Register<PropertyChangedMessage<string>>(this, message =>
2. {
3. var a = message.NewValue;
4. //do something
5. } );
5. Portable libraries
MVVM Light在不論什麽基於XAML平臺都有效。而且眼下迎來了便攜版,便攜版單獨的類庫在NuGet上。
Code Snippet
1. Install-Package Portable.MvvmLightLibs
假設你決定使用便攜版,要確定你解決方式中每個項目都要使用MVVM Light類庫引用。它跟經常使用的MVVM Light類庫並不共用。當你使用了PCL版本號,你可把你的viewmodel在單獨的、便攜式的類庫中和他們分享比方。Windows Store 或者Windows Phone app。
6. Event to Command behavior
MVVM Light有ICommand的實現叫做RelayCommand,可用於綁定行為。
比方XAML中的button有命令屬性可用於綁定在ICommand類型的datacontext,因此當button被點擊後ICommand會被啟動。
不幸的並不是全部XAML的UI元素都有可綁定的屬性用於他們可以觸發的事件並且這是EventToCommand執行的地方。通過EventToCommand 你能綁定XAML UI元素全部事件到相應viewmodel中的ICommand實現中。
首先我們須要在XAML頁面中加入兩個namespaces
First we’ll need two namespaces in our XAML page
Code Snippet
1. xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
2. xmlns:command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP8"
以下介紹我們打算在stackpanel中使用的Tap事件。
Code Snippet
1. <StackPanel Grid.Row="0" Orientation="Horizontal">
2. <i:Interaction.Triggers>
3. <i:EventTrigger EventName="Tap">
4. <command:EventToCommand Command="{Binding GoToCommand}" CommandParameter="Edit" />
5. </i:EventTrigger>
6. </i:Interaction.Triggers>
第三行指出了我們想處理的事件,註意這是一個string所以要意識到(是否)錯誤。第四行綁定命令行為而且將參數傳給了ICommand實現。
Code Snippet
1. privateRelayCommand<string> _goToCommand;
2. publicRelayCommand<string> GoToCommand
3. {
4. get { return _goToCommand jQuery15206875578026641675_1366095632942 (_goToCommand = newRelayCommand<string>(NavigateAway)); }
5. }
方法NavigateAway 例如以下所看到的。
Code Snippet
1. privatevoid NavigateAway(string parameter)
參數以使用XAML中的單詞“Edit”。我們甚至能夠在第4行中從事件到命令直接傳遞事件參數。例如以下所看到的
Code Snippet
1. <command:EventToCommand PassEventArgsToCommand="True" Command="{Binding GoToCommand}" />
Windows Store applications並沒有創造性的擁有這些行為。因此你不能使用EventToCommand除非從NuGet安裝了Win8nl toolkit。Joost Van Schaik在WinRT中創建了他自己的行為實現。感謝他的成果(還有非常多其它人在這個項目中給予幫助)我們如今能在WinRT中使用EventToCommand。
7. DispatcherHelper
自從.net4.5我們就有了await/asynckeyword而且成了同步使用的良好的一員。也就意味著假設我們打算更新UI線程的活動我們須要使用Dispatcher類以在UI線程中調用我們的行為。普通情況下我們並不須要在自己的viewmodel類中使用Dispatcher。MVVM Light包括DispatcherHelper能在須要的時候運行UI 線程行為。
Code Snippet
1. DispatcherHelper.CheckBeginInvokeOnUI(() =>
2. {
3. //do something
4. });
DispatcherHelper在App.xaml.cs或者InitializePhoneApplication(WP8項目)方法中被初始化。
DispatcherHelper相同有個RunAsync 。跟CheckBeginInvokeOnUI的不同是CheckBeginInvokeOnUI首先檢查是否已經在UI線程上了,假設在線程上就運行行為,假設不在UI線程上就調用RunAsync方法。
8. Blendable
MVVM Light有完整的Blend支持,也就是你能夠從viewmodel拖放屬性到view以生成binding,或者你能在設計時生成基於datacontext的數據。
我並不數序Blend所以也不再詳述,僅僅要心中記著MVVM Light能夠在Blend中構建就能夠了。
9. Open Source
這點你可能知道可是MVVM Light是全然開源的。假設打算下載源碼查找地址http://mvvmlight.codeplex.com/ 。
10. Laurent is on Twitter and he’s a nice guy
Laurent Bugnion,MVVM Light的創始者,也在Twitter上https://twitter.com/LBugnion
Laurent Bugnion, the founder of MVVM Light, is on Twitter! 他非常善聊也非常渴望幫助不論什麽須要幫助的人。
Conclusion
總結
MVVM Light是一個帶有些許寶石偉大的庫。在這篇文章中我討論了8個能夠讓開發人員生活簡單的有趣話題,我保留了2個額外的項目,由於10這個數字比8要好。
MVVM Light須要註意的10個問題