3.《使用Xamarin.Forms的企业应用程序模式》 - MVVM

本文详细介绍了Xamarin.Forms中使用的模型-视图-视图模型(MVVM)模式,强调了其在隔离业务逻辑与用户界面、提高测试性和可维护性方面的优势。文章详细阐述了视图、视图模型和模型的角色,以及如何连接视图模型到视图,包括声明式、编程式创建以及使用数据模板和视图模型定位器。此外,还讨论了如何更新视图以响应视图模型和模型的变化,以及使用命令和行为实现UI交互。
摘要由CSDN通过智能技术生成

模型-视图-视图模型模式

Xamarin.Forms 开发人员通常通过在 XAML 创建用户界面,并且在 code-behind 文件中添加代码来操作用户界面。 随着应用程序进行修改,代码量和范围的增加,可能出现复杂的维护问题。 这些问题包括 UI 控件和业务逻辑之间的紧密耦合,这会增加修改 UI 的代价和进行单元测试的难度。

模型-视图-视图模型 (MVVM) 模式有助于从应用程序的用户界面 (UI) 清晰隔离业务和展现逻辑。 维护应用程序逻辑与 UI 之间的清晰隔离有助于解决许多开发问题,并可以使应用程序更易于测试、 维护和改进。 它还可以显著改善代码重用机会,并允许开发人员和 UI 设计人员在开发一个应用程序的各自部分时更轻松地进行协作。

MVVM 模式

MVVM 模式中有三个核心部分: 模型(Model)、 视图(View)和视图模型(ViewModel)。 每个用于不同用途。 图 2-1 显示了三个部分之间的关系。

MVVM 模式

图 2-1:: MVVM 模式

除了了解每个部分的职责,还有必要了解它们如何互相交互。 概括的来说,视图"知道"视图模型的存在,以及视图模型"知道"模型,但模型不会意识到视图模型的存在,并且视图模型也不会意识到视图。 因此,视图模型把视图从模型中隔离开来,并允许模型独立于视图发展。

使用 MVVM 模式的好处是,如下所示:

  • 如果一个现有模型实现封装了现有业务逻辑,它可以难以修改或者带来的风险较高。 在这样的情景下,视图模型可以充当模型类的适配器,并使你可以避免对模型代码进行任何重大更改。
  • 开发人员可以为视图模型和模型创建单元测试,而无需使用对应的视图。 针对视图模型的单元测试可以运用跟视图中所使用的一致的功能。
  • 应用程序 UI 可以被重新设计,而不必触动代码,前提是该视图完全在 XAML 中实现。 因此,新版本的视图应该适用于已有的视图模型。
  • 设计人员和开发人员在开发过程中可以独立地并且同时在各自的部分工作。 设计人员可以集中精力在视图中,而开发人员可以工作在视图模型和模型部分。

有效地使用 MVVM 的关键在于了解如何将应用代码放到的正确类,并了解这些类如何进行交互。 以下章节将讨论每个类在 MVVM 模式中的职责。

视图

视图负责定义结构、 布局和外观的用户在屏幕上看到的内容。 理想情况下,每个视图都在 XAML 中定义,具有有限的 code-behind 代码,不包含业务逻辑。 但是,在某些情况下,code-behind 代码可能包含一些 XAML 中难以表达的实现了可视行为的 UI 逻辑,如动画。

在 Xamarin.Forms 应用程序中,视图通常是从 Page -派生或 ContentView -派生的类。 但是,视图也可以通过数据模板来表示,在显示对象时,它指定UI元素以可视化方式表示对象。 数据模板作为视图不具有任何 code-behind 代码,旨在绑定到特定的视图模型类型。

[!TIP]
避免在 code-behind 代码中启用和禁用 UI 元素。 请确保视图模型负责定义那些在某些方面会影响视图显示的逻辑状态变更,例如一个命令是否可用,或指示一个操作处于挂起状态。 因此,应通过绑定视图模型属性来启用和禁用UI元素,而不是在 code-behind 代码中启用和禁用它们。

有多个方式来执行视图模型上的代码以响应在视图上的交互,如按钮单击或选择某个条目。 如果一个控件支持命令,那么该控件的Command属性可以被数据绑定到视图模型的ICommand属性上。当控件的命令被调用时,将执行在视图模型中的代码。 除了命令,行为也可以被附加到视图中的对象,并且可以侦听要调用的命令或被引发的事件。 作为响应,这些行为然后可以调用视图模型上的ICommand或方法。

视图模型

视图模型实现的属性和命令可以数据绑定到视图,并通过变更通知事件来通知视图关于任何状态的更改。 视图模型提供的属性和命令定义了可提供给 UI 的功能,但视图决定了这些功能的显示方式。

[!TIP]
使用异步操作来保持 UI 响应。 移动应用程序应保持 UI 线程通畅来提高用户对性能的感知度。 因此,在视图模型中,异步方法用于 I/O 操作并引发事件异步地通知视图进行属性变更。

视图模型也负责协调视图与所需的一些模型类之间的交互。 视图模型和模型类之间通常是一对多的关系。 视图模型可能会选择直接公开模型类给视图,以便在视图中的控件可以直接与这些模型进行数据绑定。 在这种情况下,模型类将需要被设计为支持数据绑定以及变更通知事件。

每个视图模型从模型获取数据并以容易读写的方式提供给视图。 若要实现此目的,视图模型有时会执行数据转换。 将此数据转换放入视图模型是一个好主意,因为它提供给试图可以实现绑定的属性。 例如,视图模型可能组合两个属性,以简化在视图上显示。

[!TIP]
把数据转换集中在转换层。 也可以利用转换器作为一个位于视图模型与视图之间的独立数据转换层。 这也许是有必要的,例如,当数据需要特殊格式设置而视图模型不提供时。

为了使视图模型参与跟视图双向数据绑定,其属性必须引发PropertyChanged事件。 视图模型通过实现INotifyPropertyChanged接口来满足这个要求,并在属性变更时引发PropertyChanged事件。

对于集合,则为其提供了对视图友好的ObservableCollection<T>类。 此集合实现集合变更通知,从而避免开发人员在集合上实现INotifyCollectionChanged的接口。

模型

模型类是封装应用程序的数据的非可视类。 因此,该模型可以认为的代表应用的领域模型,通常包括数据模型以及业务和验证逻辑。 模型对象的示例包括数据传输对象 (Dto)、 普通旧 CLR 对象 (Poco) 和生成的实体以及代理对象。

模型类通常与封装数据访问和缓存的服务 (services) 或存储库(repositories)一起使用。

连接视图模型到视图

视图模型可以通过使用 Xamarin.Forms 的数据绑定功能连接到视图中。 有许多方法可用于构造视图和视图模型,并将其在运行时相关联。 这些方法划分为两个类别,称为视图优先(view first)组合和视图模型优先 (view model first) 组合。 两者之间的选择取决于编好和复杂度。 但是,所有方法都有一个相同的目的,这就是要有给视图的 BindingContext 属性分配一个视图模型。

对于视图优先组合的应用程序从概念上讲是由视图以及连接到它们所依赖的视图模型组成。 这种方法的主要优点是,它可用于轻松地构建松散耦合,可单元测试应用程序因为视图模型不依赖于视图本身。 它也很容易遵循其可视结构来了解应用程序的结构,而无需跟踪代码执行来了解类如何创建和关联。 此外,视图优先的构造方法符合 Xamarin.Forms 导航系统,它负责在导航发生时构造页面,这样可使视图模型优先组合的方法变得复杂且与平台偏离。

对于视图模型优先组合的应用程序从概念上讲是由视图模型组成,有一个服务来负责查找对应的视图给视图模型。 视图模型优先组合对于有些开发人员来说感觉更自然,因为视图创建可以被抽象化,让他们可以专注于应用程序的非 UI 逻辑结构。 此外,它允许视图模型通过其他视图模型来创建。 但是,这种方法通常比较复杂并且它可能会让了解应用程序的各个部分如何创建和关联变得困难。

[!TIP]
保持视图模型和视图独立。 绑定视图到数据源中的属性应该是视图对于其相应的视图模型的主要依赖。 具体而言,不要从视图模型引用视图类型,如 ButtonListView 。 按照此处列出的原则,视图模型可以被隔离测试,因此通过限制作用域来减少软件缺陷的可能性。

以下各节讨论连接视图模型到视图的主要方法。

以声明方式创建视图模型

最简单方法是在视图 XAML 中以声明方式实例化其对应的视图模型。 当构造视图时,还将构造相应的视图模型对象。 下面的代码示例演示了此方法:

<ContentPage ... xmlns:local="clr-namespace:eShop">  
    <ContentPage.BindingContext>  
        <local:LoginViewModel />  
    </ContentPage.BindingContext>  
    ...  
</ContentPage>

ContentPage 创建时,一个LoginViewModel的实例会自动构造并设置为视图的 BindingContext

此声明性构造和由该视图分配的视图模型的优点是它很简单,但它的缺点是需要视图模型中有一个默认 (无参数) 构造函数。

以编程方式创建视图模型

视图可以在 code-behind 文件中有用于分配视图模型给其 BindingContext 属性的代码。 通常在视图的构造函数中完成此操作,如下面的代码示例中所示:

public LoginView()  
{
     
    InitializeComponent();  
    BindingContext = new LoginViewModel(navigationService);  
}

在视图的 code-behind 文件中以编程方式构造和分配视图模型的优点是简单。 但是,这种方法的主要缺点是视图需要向视图模型提供所需依赖项。 使用依赖关系注入容器有助于在视图和视图模型之间保持松散耦合。 有关详细信息,请参阅依赖关系注入

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值