【簡介】html
1.做者文章:http://www.galasoft.ch/mvvm/web
2.能夠經過Nuget下載MVVLightshell
【對比引用文件】express
普通WindowsPhone引用windows
使用MVVMLight的WindowsPhone程序引用app
Microsoft.Practices.ServiceLocation:依賴注入機制的服務本地化程序集。該程序集可以經過爲依賴注入提供抽象層整合任何適合的依賴注入容器。mvvm
Systems.Windows.interactivity:事件,交互ide
【安裝完MVVMLight以後的文件結構】函數
<Application x:Class="MVVMLight學習.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="clr-namespace:MVVMLight學習.ViewModel" d1p1:Ignorable="d" > <!--應用程序資源--> <Application.Resources> <local:LocalizedStrings xmlns:local="clr-namespace:MVVMLight學習" x:Key="LocalizedStrings" /> <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" /> </Application.Resources> <Application.ApplicationLifetimeObjects> <!--處理應用程序的生存期事件所需的對象--> <shell:PhoneApplicationService Launching="Application_Launching" Closing="Application_Closing" Activated="Application_Activated" Deactivated="Application_Deactivated" /> </Application.ApplicationLifetimeObjects> </Application>
【依賴注入】post
App.Xaml中使用了ViewModelLocator進行依賴注入,代碼以下:
1 /* 2 In App.xaml: 3 <Application.Resources> 4 <vm:ViewModelLocator xmlns:vm="clr-namespace:MVVMLight.Shell" 5 x:Key="Locator" /> 6 </Application.Resources> 7 8 In the View: 9 DataContext="{Binding Source={StaticResource Locator}, Path=ViewModelName}" 10 11 You can also use Blend to do all this with the tool's support. 12 See http://www.galasoft.ch/mvvm 13 */ 14 15 using ClientService.Implements; 16 using ClientService.Interfaces; 17 using GalaSoft.MvvmLight.Ioc; 18 using Microsoft.Practices.ServiceLocation; 19 20 namespace MVVMLight.Shell.ViewModel 21 { 22 /// <summary> 23 /// This class contains static references to all the view models in the 24 /// application and provides an entry point for the bindings. 25 /// </summary> 26 public class ViewModelLocator 27 { 28 29 #region 構造函數 30 31 /// <summary> 32 /// Initializes a new instance of the ViewModelLocator class. 33 /// </summary> 34 public ViewModelLocator() 35 { 36 INavigationService navigationService = null; 37 38 /// 參數是返回值爲IServiceLocator的委託 39 ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); 40 41 ////if (ViewModelBase.IsInDesignModeStatic) 42 ////{ 43 //// // Create design time view services and models 44 //// SimpleIoc.Default.Register<IDataService, DesignDataService>(); 45 ////} 46 ////else 47 ////{ 48 //// // Create run time view services and models 49 //// SimpleIoc.Default.Register<IDataService, DataService>(); 50 ////} 51 52 //這種寫法有問題,App.RootFrame會在Application_Launching方法執行完成以後有值 53 //navigationService = new PhoneNavigationService(App.RootFrame); 54 //SimpleIoc.Default.Register<MainViewModel>(() => 55 // new MainViewModel(navigationService), false); 56 57 // 方法執行順序: 58 // 1.App構造函數 59 // 2.ViewModelLocator構造函數(App.xaml中的資源添加了ViewModelLocator) 60 // 3.App的Application_Launching方法 61 // 4.Navigate方法(App.RootFrame不爲空) 62 // 5.取得對應的ViewModel(MainViewModel),執行對應的依賴注入的委託 63 // 正確寫法,不當即注入(默認值) 64 // 此處每一個ViewModel中的navigationService相同(可考慮改進,適合使用單例模式) 65 SimpleIoc.Default.Register<MainViewModel>(() => 66 new MainViewModel(navigationService = new PhoneNavigationService(App.RootFrame)), false); 67 68 SimpleIoc.Default.Register<Page1ViewModel>(() => 69 new Page1ViewModel(navigationService), false); 70 } 71 72 #endregion 73 74 public MainViewModel Main 75 { 76 get 77 { 78 return ServiceLocator.Current.GetInstance<MainViewModel>(); 79 } 80 } 81 82 public Page1ViewModel Page1 83 { 84 get 85 { 86 return SimpleIoc.Default.GetInstance<Page1ViewModel>(); 87 } 88 } 89 90 public static void Cleanup() 91 { 92 // TODO Clear the ViewModels 93 } 94 } 95 }
【Appbar綁定Command】
使用第三方組件AppBarUtils 命令綁定
<phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar > <shell:ApplicationBarIconButton IconUri="/Assets/Images/AppBar/add.png" Text="建立磁貼"/> <shell:ApplicationBarIconButton IconUri="/Assets/Images/AppBar/Close.png" Text="刪除磁貼"> </shell:ApplicationBarIconButton> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> <i:Interaction.Behaviors> <!--Id與Button的Text對應,Type默認值爲Button--> <abu:AppBarItemCommand Type="Button" Id="建立磁貼" Command="{Binding CreateTileCommand}"></abu:AppBarItemCommand> </i:Interaction.Behaviors>
【建立動態磁貼ShellTile】
參考文章:不同凡響 windows phone (8) - Tile(磁貼)
/// <summary> /// 建立磁貼 /// </summary> public ICommand CreateTileCommand { get { return new RelayCommand(() => { if (ShellTile.ActiveTiles.Where(item => item.NavigationUri.OriginalString == "/Views/Page2.xaml?DeepLink=true").Count() > 0) { MessageBox.Show("已經添加了磁貼"); return; } StandardTileData newTile = new StandardTileData { Title = "Page2次要磁貼", //BackgroundImage = new Uri("TileBackgroundBlue.png", UriKind.Relative), Count = 2, BackTitle = "App Back Tile Title", //BackBackgroundImage = new Uri("TileBackgroundGreen.png", UriKind.Relative), BackContent = "App Back Tile Content" + Environment.NewLine + "OK" }; //shellTileService.Update(newTile); ShellTile.Create(new Uri("/Views/Page2.xaml?DeepLink=true", UriKind.Relative), newTile); }); } } /// <summary> /// 刪除磁貼 /// </summary> public ICommand DeleteTileCommand { get { return new RelayCommand(() => { var shellTile = ShellTile.ActiveTiles.First(item => item.NavigationUri.OriginalString == "/Views/Page2.xaml?DeepLink=true"); shellTile.Delete(); }); } }
【導航Navigate】
使用適配器模式,從新封裝本地的一些服務,以提供統一的訪問接口(如導航INavigationService)
【快速恢復FastResume】
參考文章:Windows phone 8 Fast Resume 快速恢復淺析(一)
程序清單文件中設置激活方式爲Resume
<Tasks> <DefaultTask Name="_default" NavigationPage="Views/MainPage.xaml" ActivationPolicy="Resume"/> </Tasks>
在App.xaml.cs文件中,註冊RootFrame.Navigating事件,以進行快速恢復的相關處理:
/// <summary> /// 快速恢復 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void FastResume(object sender, NavigatingCancelEventArgs e) { if (e.NavigationMode == NavigationMode.Reset) { isResume = true; return; } if (isResume && e.NavigationMode == NavigationMode.New) { isResume = false; if (!e.Uri.ToString().Contains("DeepLink=true")) { e.Cancel = true; } } }
【獨立存儲】
參考:Windows Phone 獨立存儲之IsolatedStorageSettings
【墓碑恢復】
1 using Microsoft.Phone.Controls; 2 using System.Windows.Navigation; 3 4 namespace PhoneClient.Adapters.Interfaces 5 { 6 public interface INavigationService 7 { 8 #region 屬性 9 10 PhoneApplicationFrame Frame 11 { 12 get; 13 } 14 15 #endregion 16 17 #region 事件 18 19 event NavigatedEventHandler Navigated; 20 event NavigatingCancelEventHandler Navigating; 21 22 #endregion 23 24 #region 方法 25 26 void NavigateTo(string url); 27 28 #endregion 29 } 30 }
1 using System; 2 using System.Windows.Navigation; 3 4 using Microsoft.Phone.Controls; 5 using PhoneClient.Adapters.Interfaces; 6 7 namespace PhoneClient.Adapters.Implements 8 { 9 public class NavigationServiceAdapter : INavigationService 10 { 11 #region 字段 12 13 private PhoneApplicationFrame frame; 14 15 #endregion 16 17 #region 事件 18 19 public event NavigatedEventHandler Navigated; 20 public event NavigatingCancelEventHandler Navigating; 21 22 #endregion 23 24 #region 構造函數 25 26 public NavigationServiceAdapter(PhoneApplicationFrame frame) 27 { 28 this.frame = frame; 29 this.frame.Navigating += frame_Navigating; 30 this.frame.Navigated += frame_Navigated; 31 } 32 33 #endregion 34 35 #region 方法 36 37 void INavigationService.NavigateTo(string url) 38 { 39 if (this.frame != null) 40 { 41 this.frame.Navigate(new Uri(url, UriKind.Relative)); 42 } 43 } 44 45 void frame_Navigating(object sender, NavigatingCancelEventArgs e) 46 { 47 if (Navigating != null) 48 { 49 Navigating(sender, e); 50 } 51 } 52 53 void frame_Navigated(object sender, NavigationEventArgs e) 54 { 55 if (Navigated != null) 56 { 57 Navigated(sender, e); 58 } 59 } 60 61 #endregion 62 63 PhoneApplicationFrame INavigationService.Frame 64 { 65 get 66 { 67 return frame; 68 } 69 } 70 } 71 }
1 using System.Linq; 2 3 using GalaSoft.MvvmLight; 4 using MVVMLight.Shell.Common.StorageHelper; 5 using PhoneClient.Adapters.Interfaces; 6 using System; 7 8 namespace MVVMLight.Shell.ViewModels 9 { 10 public class ViewModel : ViewModelBase 11 { 12 #region 字段 13 14 private INavigationService navigationService; 15 16 private Uri pageUri; 17 18 #endregion 19 20 #region 構造方法 21 22 public ViewModel(INavigationService navigationService, Uri pageUri) 23 { 24 if (navigationService != null) 25 { 26 this.navigationService = navigationService; 27 this.pageUri = pageUri; 28 this.navigationService.Navigating += navigationService_Navigating; 29 this.navigationService.Navigated += navigationService_Navigated; 30 } 31 } 32 33 #endregion 34 35 #region 私有方法 36 37 private void navigationService_Navigating(object sender, System.Windows.Navigation.NavigatingCancelEventArgs e) 38 { 39 // 保存程序狀態 40 if (e.Uri.OriginalString == "app://external/") 41 { 42 OnPageDeactivation(); 43 IsolatedStorageHelper.SettingSave<bool>("tombstone", true); 44 } 45 } 46 47 private void navigationService_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e) 48 { 49 // 墓碑恢復 50 if (e.Uri.OriginalString != "app://external/" && IsolatedStorageHelper.SettingLoad<bool>("tombstone") == true) 51 { 52 OnPageResumeFromTombstone(); 53 54 // 全部頁面都從墓碑狀態恢復以後刪除獨立存儲中的墓碑標識 55 if (this.navigationService.Frame.BackStack.Count() == 0) 56 { 57 IsolatedStorageHelper.SettingRemove("tombstone"); 58 } 59 } 60 61 // 判斷當前導航的頁面與ViewModel是否對應 62 if (this.pageUri.OriginalString == e.Uri.OriginalString) 63 { 64 OnNavigatedTo(); 65 } 66 } 67 68 #endregion 69 70 #region 方法 71 72 public virtual void OnPageDeactivation() 73 { 74 75 } 76 77 public virtual void OnPageResumeFromTombstone() 78 { 79 80 } 81 82 public virtual void OnNavigatedTo() 83 { 84 85 } 86 87 #endregion 88 89 } 90 }