65.9K
CodeProject 正在变化。 阅读更多。
Home

Mvvmcross Platform 入门

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (7投票s)

2015 年 1 月 10 日

CPOL

7分钟阅读

viewsIcon

33693

在本文中,我将对 mvvmcross 平台的基本概念进行简要概述。我们将探讨 mvvmcross 项目架构和一些 mvvmcross 类。

引言

Mvvmcross 是一个 MVVM 平台,可以解决你在开发跨平台(如 Android、Windows Phone 或 IOS)时迟早会遇到的许多问题。

问题在于,每个平台都有自己的规范,因此你无法简单地编写一个代码并在多个平台上运行。这时 Xamarin 就变得非常方便了。

mvvmcross 的主要特点是,你不仅将逻辑与视图分离(如 MVVM MVC 模式),还将其与特定平台实现分离。

你的业务逻辑将在 PCL(可移植类库)中实现,每个平台都可以将其作为自己的逻辑来引用,同时相应地实现其原生端。

查看 mvvmcross manifest

https://github.com/MvvmCross/MvvmCross/wiki/The-MvvmCross-Manifesto

Mvvmcross 在 Github 上

https://github.com/MvvmCross/MvvmCross

*在此特定示例中,我将展示 mvvmcross 在 Windows 8.1 应用商店应用上的实现。

MVVM 模式

熟悉 MVC 模式的人会发现它与 MVVM 相似,因为它旨在解决相同的问题,但方式略有不同。 

MVC 将程序分为三个模块:视图、控制器和模型,MVVM 则通过匹配视图与适当的 ViewModel 来耦合视图及其逻辑。这使得你的软件设计更加灵活,因为 View ViewModel 之间的唯一依赖关系是通过 Binding 建立的。

视图和代码逻辑的硬编码依赖(如 codebehind 方法中使用)会限制应用程序的动态性,因为视图和代码以直接的方式耦合。

对于完全不熟悉此概念的人,我建议您访问以下链接:

http://en.wikipedia.org/wiki/Model_View_ViewModel

http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller

为什么选择 MVVM?

一旦你将应用程序设计为 MVVM 模式,你就可以简单地替换一个视图,只需保持 Binding 约定,而不必修改逻辑。

反之亦然,你可以在不修改 View 的情况下切换 ViewModels

在使用 codebehind 方法时,这要困难得多(几乎不可能)。

在我们的示例中,我们使用 MVVM 模式,但此外,我们将逻辑从特定应用程序分离到 PCL 库。这将使我们能够在 Xamarin 的不同平台(如 Android、IOS 和 Windows Phone)上使用相同的库。

安装 mvvmcross nugget 

在“管理 Nugget 包”窗口中搜索 mvvmcross,确保将其安装在 PCL 和应用程序项目上。

或者,直接输入

PM> Install-Package MvvmCross.HotTuna.Plugin.All -Version 3.2.2

在你的包管理器控制台中。

随着 nugget 完成安装,请注意,你的 PCL 和应用程序项目中会出现两个名为“ToDo-MvvmCross”的新目录,请逐步按照说明进行操作。

如果一切顺利,你可以编译并运行你的应用程序。你应该会得到类似这样的结果

探索 mvvmcross 项目结构

 

可移植类库 (PCL)

App.cs 

这是你的 PCL 的主类,它继承自 MvxApplication,并且会在你的库创建时实例化一次。

Initialize() 方法

        public override void Initialize()
        {
            CreatableTypes()
                .EndingWith("Service")
                .AsInterfaces()
                .RegisterAsLazySingleton();
            RegisterAppStart<ViewModels.FirstViewModel>();
        }

此方法将遍历库项目中的所有类,并且所有以“Service”约定结尾的类都将作为单例使用 惰性实例化在你的 Mvx 对象中。

当然,你也可以手动完成

//Using Func
Mvx.RegisterType<TestService>(() => new TestService());
//using Interface as identifier
Mvx.RegisterSingleton<ITestservice>(new TestService());


你可以根据需要更改 Initialize 方法。

例如:

            CreatableTypes()
                .EndingWith("Handler")
                .AsTypes()
                .RegisterAsLazySingleton();

解释:现在它将遍历所有以“Handler”结尾的类,并使用惰性实例化,将它们注册为类型,而不是接口。

同时请注意,我们指定了应用程序将启动的 ViewModel。

RegisterAppStart<ViewModels.FirstViewModel>();

 

mvvmcross 中的依赖注入/IOC

依赖注入是一种 软件设计模式,其中一个或多个依赖项在解析对象类型时被注入或通过 引用 传递。

 

注册类型和接口

在 mvvmcross 中,Mvx 类有三种注册对象的方式:

RegisterType – 根据你选择的重载函数,按接口或构造函数注册类型。

RegisterSingleTone – 将对象注册为单例(整个应用程序生命周期只有一个实例)。

LazyConstructorAndRegistersingleTon – 将对象注册为单例,并进行惰性构造函数实例化。这意味着,只有在调用 Mvx 类的 Resolve() 方法时,对象才会被实例化。

在 mvvmcross 中,有一个名为 Mvx 的类,它使用 IOC 来注册和解析依赖项。

 

解析类型和接口

你只能通过 Resolve() 方法解析已注册的对象,通过指定类型或接口。

建议先使用 CanResolve 方法或 TryResolve ,以确保不会抛出恼人的异常。

在通过 CreateTypes 方法或手动将类型注册到 Mvx 类后,你现在可以从应用程序中的任何位置访问这些类。

var filehandler = Mvx.Resolve<IFileHandlerAsync>();

 

有关更多信息,请参阅以下链接:

IOC - http://en.wikipedia.org/wiki/Inversion_of_control

DI - http://en.wikipedia.org/wiki/Dependency_injection

 

ViewModels 目录

mvvmcross nugget 自动添加的另一个组件是你库项目中的 ViewModels 目录。

所有 ViewModel 类(继承自 MvxViewModel)都存储在此处,并将通过名称约定链接到应用程序项目中的视图。

请注意,默认情况下,mvvmcross nugget 会在你的 ViewModels 目录中创建一个 FirstViewModel.cs 类,该类最终会链接到应用程序项目中 Views 目录中的 FirstView.cs。

名称约定是:

视图约定:[视图名称].cs 

ViewModel 约定:[视图名称]Model.cs

 

MvxViewModel 和 MvxWindowsPage

在使用 mvvmcross 时,你将处理 Mvx 类,每个 ViewModel 类都继承自 MvxViewModel,每个 View 都继承自 MvxWindowsPage

在遵循 MVVM 模式时,我们不会在 View 类中编写任何 codebehind,因此视图的全部逻辑将在相应的 ViewModel 中实现。

MvxViewModel 方法

public virtual void Start()

Init() 是在 ViewModel 中调用的第一个方法。

public void Init(IMvxBundle parameters)

Start()Init() 方法之后调用,IMvxBundle 参数是一个对象,其中来自前一个 ViewModel 的 passed 数据作为 Key-Vaule 对传递,使用 Dictionary 作为数据结构。

所有传递的数据都存储为字符串,因此要与复杂对象一起使用,你需要执行序列化,这可能会严重影响性能。

通常,在处理复杂对象时,会使用另一个辅助类来完成这些任务。

public void Init(IMvxBundle parameters);
protected virtual void InitFromBundle(IMvxBundle parameters);
protected virtual void ReloadFromBundle(IMvxBundle state);
public void ReloadState(IMvxBundle state);
public void SaveState(IMvxBundle state);
protected virtual void SaveStateToBundle(IMvxBundle bundle);

这些方法用于从 bundle 存储和重新加载数据。通常在你应用程序进入后台,并且你希望保存一些可能丢失的数据时使用,因为 ViewModel 将被重新初始化。 当应用程序返回到前台时,保存的数据将被读取并如同 ViewModel 重新加载一样被处理。

调用顺序

ViewModel 创建

  1. 构造函数 () 
  2. Init()
  3. InitFromBundle()
  4. Start()

ViewModel 销毁

SaveStateToBundle()

 

应用程序项目

在我们的应用程序项目中,我们有一个名为 Views 的新目录、DebugTrsace.cs 类和 Setup.cs。

DebugTrace

继承自 IMvxTrace 接口,该接口实现了 3 个方法。

void Trace(MvxTraceLevel level, string tag, Func<string> message);
void Trace(MvxTraceLevel level, string tag, string message);
void Trace(MvxTraceLevel level, string tag, string message, params object[] args);

使用 System.Diagnostics.Debug 类进行日志记录。

安装

这是应用程序设置发生的地方。

这些是方法:

        public Setup(Frame rootFrame) : base(rootFrame)
        protected override IMvxApplication CreateApp()
        protected override IMvxTrace CreateDebugTrace()

Setup - Setup 类的构造函数。

CreateDebugTrace – 在创建 DebugTrace 时调用,默认情况下 – 只返回 DebugTrace 类的实例。

CreateApp – 在整个应用程序初始化并建立 mvvmcross 组件连接之前立即调用。在这里,你可以从应用程序项目注册到 IOC,并在 PCL 中使用 Mvx 类中的那些对象。

例如,如果你想从可移植库中的 ViewModel 调用 DialogMessage 对象,你无法通过直接调用该类来建立。因为你的项目没有相应的程序集引用。

在这种情况下,你可以创建实现某种功能的类,并在 CreateApp 方法完成之前,将其注册到共享的 Mvx (IOC)对象。

protected override IMvxApplication CreateApp()
{
       Mvx.RegisterSingleton<IMessageBox>(new MessageBoxHandler());
       return new Core.App();
}

在 PCL 项目中声明接口,以便两个项目都能识别它。

ViewModel 中,简单调用 Mvx 类的 Resolve 方法来获取所需的 Mvx 对象实例。

Mvx.Resolve<IMessageBox>().ShowMessage(COMMENT_SUBMIT_SUCCESS);

现在,你的 ViewModel 中就有 DialogMessage 功能了。

视图

在你的 xaml 视图中,你可以看到基础 xaml 节点不再是 Page,而是 views:MvxWindowsPage,它是 mvvmcross 类型,codebehind 也继承自同一个类。

现在你可以创建你的视图并将控件绑定到 ViewModel(位于 PCL 中)。

摘要

Mvvmcross 是一个非常方便的跨平台应用程序开发平台,它使你的开发过程更加简单。

继续阅读有关 mvvmcross 插件和扩展的内容。还有很多值得探索的地方。

© . All rights reserved.