【简介】
1.作者文章:http://www.galasoft.ch/mvvm/
2.可以通过Nuget下载MVVLight
【对比引用文件】
普通WindowsPhone引用
使用MVVMLight的WindowsPhone程序引用
Microsoft.Practices.ServiceLocation:依赖注入机制的服务本地化程序集。该程序集能够通过为依赖注入提供抽象层整合任何适合的依赖注入容器。
Systems.Windows.interactivity:事件,交互
【安装完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>
【依赖注入】
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 }