基于Prism.Windows的UWP开发备忘

以前做UWP开发都是使用MvvmLight,主要是简单易上手,同时也写了很多MvvmLight的开发系列文章:

UWP开发必备以及常用知识点总结

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)
{&nbsp;&nbsp;&nbsp;&nbsp; _navigationService = navigationService;
}
&nbsp;

总结二:自动绑定

自动绑定的命名规则:

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"

x:Class="PrismUnityApp1.Views.MainPage"
             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

全部接口:

  1. bool Navigate(string pageToken, object parameter);
  2. void GoBack();
  3. bool CanGoBack();
  4. void GoForward();
  5. bool CanGoForward();
  6. void ClearHistory();
  7. void RemoveFirstPage(string pageToken = null, object parameter = null);
  8. void RemoveLastPage(string pageToken = null, object parameter = null);
  9. void RemoveAllPages(string pageToken = null, object parameter = null);
  10. void RestoreSavedNavigation();
  11. void Suspending();

有了它再也不用担心一些特殊的页面漂移问题。

1,App.cs内部使用。(类以及包含NavigationService成员属性):

// 启动页面表示
NavigationService.Navigate("Home", null);

2,ViewModel使用。

private INavigationService _navigationService;

        public HomePageViewModel(INavigationService navigationService)
        {
            _navigationService = navigationService;
        }
&nbsp;
_navigationService.ClearHistory()等
&nbsp;

注意:

由于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()
{&nbsp;&nbsp;&nbsp;&nbsp;

SessionStateService.RegisterKnownType(typeof(FavoriteInfo));    SessionStateService.RegisterKnownType(typeof(ServerInfo));// 这个比较重要SessionStateService.RegisterKnownType(typeof(ObservableCollection<FavoriteInfo>));

}

2,ViewPage类型设置

<prismMvvm:

SessionStateAwarePage

x:Class="PrismUnityApp1.Views.SettingPage"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns:d="http://schemas.microsoft.com/expression/blend/2008"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns:prismMvvm="using:Prism.Windows.Mvvm"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; prismMvvm:ViewModelLocator.AutoWireViewModel="True"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
mc:Ignorable="d">
&nbsp;

3,ViewModel中数据成员属性设置

&nbsp;
private ObservableCollection<FavoriteInfo> _favoriteFolders;
[

RestorableState

]
public ObservableCollection<FavoriteInfo> FavoriteFolders
{&nbsp;&nbsp;&nbsp;&nbsp;
get&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return _favoriteFolders;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;
set&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetProperty(ref _favoriteFolders, value);&nbsp;&nbsp;&nbsp;&nbsp; }
}
&nbsp;

4,.net native相关的Default.rd.xml设置

<Type Name="PrismUnityApp1.DataModels.FavoriteInfo"

DataContractSerializer

="Required Public" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<Namespace Name="System.Collections.ObjectModel" >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<TypeInstantiation Name="ObservableCollection"&nbsp; Arguments="PrismUnityApp1.DataModels.FavoriteInfo"

DataContractSerializer

="Required Public" />&nbsp;&nbsp;&nbsp;&nbsp;
</Namespace>
&nbsp;

总结五: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

&nbsp;

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); }
}
&nbsp;

3,控件绑定

<TextBox Text="{Binding Name, Mode=TwoWay}" Header="Name" />
<TextBlock Text="{Binding

Errors[Name][0]

}" Foreground="Red" HorizontalAlignment="Right" />
&nbsp;
<ItemsControl x:Name="ErrorList" ItemsSource="{Binding

Errors.Errors

}" />
&nbsp;

备注:通过继承ValidationAttribute 可以自定义各种验证逻辑。

&nbsp;

总结七:菜单设置时机

App.cs内部的CreateShell方法中设置:

protected override UIElement CreateShell(Frame rootFrame)
        {
            var menuPage = Container.Resolve<MenuPage>();
            menuPage.NavigationFrame.Content = rootFrame;
            return menuPage;
        }
&nbsp;

总结八:数据库创建时机

以前我们一般都是在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 InitializeFrameAsync(IActivatedEventArgs args)
        {
createDBAsync();
return base.InitializeFrameAsync(args);
        }

基本就这些东西,总结一下方便以后开发,同时也希望对园友们有帮助。

相关推荐