以前做UWP開發都是使用MvvmLight,主要是簡單易上手,同時也寫了很多MvvmLight的開發系列文章:
UWP開發之Mvvmlight實踐九:基於MVVM的項目架構分享
UWP開發之Mvvmlight實踐八:為什么事件注銷處理要寫在OnNavigatingFrom中
UWP開發之Mvvmlight實踐七:如何查找設備(Mobile模擬器、實體手機、PC)中應用的Log等文件
UWP開發之Mvvmlight實踐六:MissingMetadataException解決辦法(.Net Native下Default.rd.xml配置問題)
UWP開發之Mvvmlight實踐五:SuspensionManager中斷掛起以及復原處理
UWP開發之Mvvmlight實踐四:{x:bind}和{Binding}區別詳解
UWP開發之Mvvmlight實踐三:簡單MVVM實例開發(圖文詳解付代碼)
UWP開發之Mvvmlight實踐二:Mvvmlight的核心框架MVVM與MVC、MVP的區別(圖文詳解)
UWP開發之Mvvmlight實踐一:如何在項目中添加使用Mvvmlight(圖文詳解)
出於開發效率考慮,以后打算都使用Prism或者Template10開發,其中很多的實現原理與MvvmLight相似。此次基於Prism.Windows完成的UWP應用雖然功能不是那么復雜,但是基本上用全了Prism的優良特性,特寫下次篇做備忘。
總結一:IOC控制反轉容器
目前只支持Unity,SimpleInjector,Autofac三個,相比MvvmCross或者Mvvmlight框架則選擇更加靈活。
使用方法(例如:Unity):
1,App類繼承於IOC對應的Application類。
sealed partial class App : PrismUnityApplication
{}
2,依賴注入。(最好所有的注入都寫在這個方法里面,后續的啟動處理以及頁面轉移等可以立馬使用。)
protected override Task OnInitializeAsync(IActivatedEventArgs args)
{
Container.RegisterInstance<INavigationService>(NavigationService);
Container.RegisterInstance<ISessionStateService>(SessionStateService);
Container.RegisterType<ISettingService, SettingService>(new ContainerControlledLifetimeManager());
return base.OnInitializeAsync(args);
}
3,調用。
- App.cs內調用:
await Container.Resolve<IAppStartupService>().CreateDataBaseAsync();
- ViewModel內使用:
private INavigationService _navigationService;
public HomePageViewModel(INavigationService navigationService)
{ _navigationService = navigationService;
}
總結二:自動綁定
自動綁定的命名規則:
View名:HomePage
ViewModel名:HomePageViewModel
其次Views與ViewModels文件夾最好在同一個程序集下,然后View的頭部添加如下兩行代碼,就可以自動綁定ViewModel。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
Title="MainPage">
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<Label Text="{Binding Title}" />
</StackLayout>
</ContentPage>
如果View與ViewModel分層了,通過自定義ViewModelTypeResolver也可以實現自動綁定。
ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver(
viewType => {
// 自由設置
return Type.GetType("");
});
Prism.Mvvm下ViewModelLocationProvide.cs的默認設置如下:
static Func<Type, Type> _defaultViewTypeToViewModelTypeResolver =
viewType =>
{
var viewName = viewType.FullName;
viewName = viewName.Replace(".Views.", ".ViewModels.");
var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
var suffix = viewName.EndsWith("View") ? "Model" : "ViewModel";
var viewModelName = String.Format(CultureInfo.InvariantCulture, "{0}{1}, {2}", viewName, suffix, viewAssemblyName);
return Type.GetType(viewModelName);
};
總結三:NavigationService
全部接口:
- bool Navigate(string pageToken, object parameter);
- void GoBack();
- bool CanGoBack();
- void GoForward();
- bool CanGoForward();
- void ClearHistory();
- void RemoveFirstPage(string pageToken = null, object parameter = null);
- void RemoveLastPage(string pageToken = null, object parameter = null);
- void RemoveAllPages(string pageToken = null, object parameter = null);
- void RestoreSavedNavigation();
- void Suspending();
有了它再也不用擔心一些特殊的頁面漂移問題。
1,App.cs內部使用。(類以及包含NavigationService成員屬性):
// 啟動頁面表示
NavigationService.Navigate("Home", null);
2,ViewModel使用。
private INavigationService _navigationService;
public HomePageViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
}
_navigationService.ClearHistory()等
注意:
由於10,11 的記錄保存與復原都是使用DataContractSerializer序列化,所以頁面漂移參數最好使用字符串或者數字。
總結四:中斷還原處理
SessionStateService是類似SuspensionManager專門處理中斷。
1,App.cs內部設置
依賴注入
protected override Task OnInitializeAsync(IActivatedEventArgs args)
{
Container.RegisterInstance<ISessionStateService>(SessionStateService);
return base.OnInitializeAsync(args);
}
類型注冊
protected override void OnRegisterKnownTypesForSerialization()
{
SessionStateService.RegisterKnownType(typeof(FavoriteInfo));
SessionStateService.RegisterKnownType(typeof(ServerInfo));
// 這個比較重要
SessionStateService.RegisterKnownType(typeof(ObservableCollection<FavoriteInfo>));
}
2,ViewPage類型設置
<prismMvvm:SessionStateAwarePage
x:Class="PrismUnityApp1.Views.SettingPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:prismMvvm="using:Prism.Windows.Mvvm" prismMvvm:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
3,ViewModel中數據成員屬性設置
private ObservableCollection<FavoriteInfo> _favoriteFolders;
[RestorableState]
public ObservableCollection<FavoriteInfo> FavoriteFolders
{
get { return _favoriteFolders; }
set { SetProperty(ref _favoriteFolders, value); }
}
4,.net native相關的Default.rd.xml設置
<Type Name="PrismUnityApp1.DataModels.FavoriteInfo" DataContractSerializer="Required Public" />
<Namespace Name="System.Collections.ObjectModel" >
<TypeInstantiation Name="ObservableCollection" Arguments="PrismUnityApp1.DataModels.FavoriteInfo" DataContractSerializer="Required Public" />
</Namespace>
總結五:ResourceLoader
1,依賴注入。
protected override Task OnInitializeAsync(IActivatedEventArgs args)
{
Container.RegisterInstance<IResourceLoader>(new ResourceLoaderAdapter(new ResourceLoader()));
return base.OnInitializeAsync(args);
}
2,調用GetString()獲取數據。
public MenuViewModel(INavigationService navigationService,
IResourceLoader
resourceLoader)
{
_navigationService = navigationService;
Commands = new ObservableCollection<MenuItemViewModel>
{
new MenuItemViewModel { DisplayName = resourceLoader.GetString("MainPageMenuItemDisplayName"), FontIcon = "\ue15f", Command = new DelegateCommand(NavigateToMainPage, CanNavigateToMainPage) },
new MenuItemViewModel { DisplayName = resourceLoader.GetString("SecondPageMenuItemDisplayName"), FontIcon = "\ue19f", Command = new DelegateCommand(NavigateToSecondPage, CanNavigateToSecondPage) }
};
}
總結六:屬性驗證Validatable
類似Asp.net MVC支持以下Validation:
- Required
- CreditCard
- EmailAddress
- PhoneNumber
- Range
- MinLength
- MaxLenght
- RegularExpression
- Enumeration
- URL
使用方法:1,繼承與ValidatableBindableBase
public class Address :
ValidatableBindableBase
2,成員設置:
[Required(ErrorMessage = "Name is required.")]
public string Name
{
get { return name; }
set { SetProperty(ref name, value); }
}
[RegularExpression(@"[ABCD]\d{2,5}", ErrorMessage="Location is Quadrant (A -> D) and Sector (2 -> 5 digits)")]
public string Location
{
get { return location; }
set { SetProperty(ref location, value); }
}
3,控件綁定
<TextBox Text="{Binding Name, Mode=TwoWay}" Header="Name" />
<TextBlock Text="{Binding Errors[Name][0]}" Foreground="Red" HorizontalAlignment="Right" />
<ItemsControl x:Name="ErrorList" ItemsSource="{Binding Errors.Errors}" />
備注:通過繼承ValidationAttribute 可以自定義各種驗證邏輯。
總結七:菜單設置時機
App.cs內部的CreateShell方法中設置:
protected override UIElement CreateShell(Frame rootFrame)
{
var menuPage = Container.Resolve<MenuPage>();
menuPage.NavigationFrame.Content = rootFrame;
return menuPage;
}
總結八:數據庫創建時機
以前我們一般都是在OnLaunched方法內部添加如下代碼實現:
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
// 不要在窗口已包含內容時重復應用程序初始化,
// 只需確保窗口處於活動狀態
if (rootFrame == null)
{
// 創建要充當導航上下文的框架,並導航到第一頁
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: 從之前掛起的應用程序加載狀態
}
// 將框架放在當前窗口中
Window.Current.Content = rootFrame;
}
if (e.PrelaunchActivated == false)
{
if (rootFrame.Content == null)
{
// 數據庫創建
createDBAsync();
// 當導航堆棧尚未還原時,導航到第一頁,
// 並通過將所需信息作為導航參數傳入來配置
// 參數
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
// 確保當前窗口處於活動狀態
Window.Current.Activate();
}
}
Task createDBAsync()
{
// 略
return Task.FromResult(true);
}
由於Prism封裝了Application類,所以代碼添加的位置也變了:
protected override Task OnInitializeAsync(IActivatedEventArgs args)
{
createDBAsync();
return base.OnInitializeAsync(args);
}
基本就這些東西,總結一下方便以后開發,同時也希望對園友們有幫助。
