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

MvvmCross TipCalc - 步骤 1:创建核心可移植应用程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (9投票s)

2013 年 3 月 23 日

Ms-PL

6分钟阅读

viewsIcon

70587

MvvmCross v3 - Hot Tuna 的 TipCalc 教程的步骤 1。

介绍  

本文是 MvvmCross v3 - Hot Tuna! 的 TipCalc 教程的第一步。

开始可移植开发

MvvmCross 应用程序通常的结构是:

  • 一个共享的“核心”可移植类库 (PCL) 项目
    • 包含尽可能多的代码:模型、视图模型、服务、转换器等。
  • 每个平台一个 UI 项目
    • 每个项目包含该平台的引导程序和特定于视图的代码。

通常,您从核心项目开始开发——这正是我们在这里要做的事情。

要创建核心,您可以使用 Visual Studio 项目模板向导,但在这里我们将从“空项目”开始构建一个新项目。

创建可移植类库

使用 Visual Studio,通过“文件 | 新建项目”向导创建您的新 PCL。

将其命名为 TipCalc.Core.csproj 之类的名称。

当被要求选择平台时,请选择所有 WindowsPhone、WindowsStore (.NET 4.5)、Xamarin.Android 和 Xamarin.iOS——这将确保 PCL 位于 Profile104。此配置文件定义了一小部分 .NET,其中包含以下程序集的组成部分:

  • mscorlib
  • System.Core
  • System.Net
  • System.Runtime.Serialization
  • System.ServiceModel
  • System.Windows
  • System.Xml
  • System.Xml.Linq
  • System.Xml.Serialization

对我们来说重要的是,Profile104 包含了构建 Mvvm 应用程序所需的一切。

删除 Class1.cs

没有人真正需要 Class1微笑 | <img src= " align="top" src="https://codeproject.org.cn/script/Forums/Images/smiley_smile.gif" />

添加对 CrossCore 和 MvvmCross 程序集的引用

使用“添加引用”来链接这两个可移植类库。

  • Cirrious.CrossCore.dll
    • 核心接口和概念,包括跟踪、IoC 和插件管理
  • Cirrious.MvvmCross.dll
    • Mvvm 类 - 包括 MvxApplication MvxViewModels 的基类。

通常,这些文件会位于类似 {SolutionRoot}/Libs/Mvx/Portable/ 的文件夹路径中。

添加小费计算服务

创建一个名为“Services”的文件夹。

在此文件夹中,创建一个新的接口,用于计算小费。

public interface ICalculation
{
    double TipAmount(double subTotal, int generosity);
}

在此文件夹中,创建此接口的实现。

public class Calculation : ICalculation
{
    public double TipAmount(double subTotal, int generosity)
    {
        return subTotal * ((double)generosity)/100.0;
    }
}

这为我们的应用程序提供了一些简单的业务逻辑。

添加 ViewModel

从草图层面来看,我们希望有一个用户界面,它:

  • 使用
    • 我们的计算服务来计算小费。
  • 有以下输入:
    • 当前账单(subTotal)
    • 对我们想留下多少小费的感知(generosity)。
  • 有以下输出显示:
    • 要留下的小费金额。

为了表示这个用户界面,我们需要为用户界面构建一个“模型”——当然,这就是“ViewModel”。

在 MvvmCross 中,所有 ViewModel 都应继承自 MvxViewModel

所以现在,在我们的项目中创建一个 ViewModels 文件夹,并在该文件夹中添加一个名为 TipViewModel 的新类,如下所示:

using Cirrious.MvvmCross.ViewModels;

namespace TipCalc.Core
{
    public class TipViewModel : MvxViewModel
    {
        private readonly ICalculation _calculation;
        public TipViewModel(ICalculation calculation)
        {
            _calculation = calculation;
        }

        public override void Start()
        {
            _subTotal = 100;
            _generosity = 10;
            Recalcuate();
            base.Start();
        }

        private double _subTotal;

        public double SubTotal
        {
            get { return _subTotal; }
            set { _subTotal = value; RaisePropertyChanged(() => SubTotal); Recalcuate(); }
        }

        private int _generosity;

        public int Generosity
        {
            get { return _generosity; }
            set { _generosity = value; RaisePropertyChanged(() => Generosity); Recalcuate(); }
        }

        private double _tip;

        public double Tip
        {
            get { return _tip; }
            set { _tip = value; RaisePropertyChanged(() => Tip);}
        }

        private void Recalcuate()
        {
            Tip = _calculation.TipAmount(SubTotal, Generosity);
        }
    }
}

对你们中的许多人来说,这个 TipViewModel 已经很清楚了。如果不是,那么请跳到“创建应用程序”。如果不是,那么这里有一些简单的解释:

  • TipViewModel 是通过一个 ICalculation 服务构造的。

    private readonly ICalculation _calculation;
    
    public TipViewModel(ICalculation calculation)
    {
        _calculation = calculation;
    }
  • 构造完成后,TipViewModel 将被启动——在此过程中,它会设置一些初始值。

    public override void Start()
    {
        // set some start values
        SubTotal = 100.0;
        Generosity = 10;
        Recalculate();
    }
  • TipViewModel 中包含的视图数据通过属性公开。

    • 这些属性中的每一个都由一个 private 成员变量支持。
    • 这些属性中的每一个都有 get set
    • Tip 的 set 访问器被标记为 private
    • 所有 set 访问器都调用 RaisePropertyChanged 来通知基类 MvxViewModel 数据已更改。
    • SubTotal Generosity set 访问器还调用 Recalculate()

      private double _subTotal;
      public double SubTotal
      {
          get { return _subTotal; }
          set {  _subTotal = value; 
          	RaisePropertyChanged(() => SubTotal); Recalculate(); }
      }
      
      private int _generosity;
      public int Generosity
      {
          get { return _generosity; }
          set {  _generosity = value; 
          	RaisePropertyChanged(() => Generosity); Recalculate(); }
      }
      
      private double _tip;
      public double Tip
      {
          get { return _tip; }
          private set {  _tip = value; RaisePropertyChanged(() => Tip); }
      }
  • Recalculate 方法使用 _calculation 服务根据 SubTotal Generosity 的当前值更新 Tip

    private void Recalculate()
    {
        Tip = _calculation.TipAmount(SubTotal, Generosity);
    }

添加应用程序 (App)

在定义了 Calculation 服务和 TipViewModel 之后,我们现在只需要添加主要的 App 代码。

  • 这段代码将位于我们 PCL 核心项目根文件夹中的单个类中。
  • 这个类将继承自 MvxApplication 类。
  • 这个类通常就叫 App。
  • 这个类负责提供:
    • 应用程序使用的接口和实现注册。
    • 应用程序启动时显示的 ViewModel 注册。
    • ViewModel 定位的控制——尽管大多数应用程序通常只使用基类 MvxApplication 提供的默认实现。

这里的“注册”意味着创建一个“控制反转”——IoC——记录,用于一个接口。这个 IoC 记录告诉 MvvmCross 框架当任何代码请求该接口的实例时应该做什么。

对于我们的 Tip Calculation App:

  • 我们将 Calculation 类注册为实现 ICalculation 服务。

    Mvx.RegisterType<ICalculation, Calculation>();

    这一行告诉 MvvmCross 框架,当任何代码请求 ICalculation 引用时,框架应该创建一个新的 Calculation 实例。

  • 我们希望应用程序从 TipViewModel 开始。

    var appStart = new MvxAppStart<TipViewModel>();
    Mvx.RegisterSingleton<IMvxAppStart>(appStart);

    这一行告诉 MvvmCross 框架,当任何代码请求 IMvxAppStart 引用时,框架应该返回同一个 appStart 实例。

所以 App.cs 看起来是这样的:

using Cirrious.CrossCore.IoC;
using Cirrious.MvvmCross.ViewModels;

namespace TipCalc.Core
{
    public class App : MvxApplication
    {
        public App()
        {
            Mvx.RegisterType<ICalculation,Calculation>();
            Mvx.RegisterSingleton<IMvxAppStart>(new MvxAppStart<TipViewModel>());
        }
    }
}

注意:什么是“控制反转”?

我们在这里不深入探讨 IoC——控制反转——是什么。

相反,我们只说:

  • 在每个 MvvmCross 应用程序中,都有一个单一的特殊对象——单例。
  • 这个单例存在于 Mvx static 类中。
  • 应用程序启动代码可以使用 Mvx.Register 方法来指定在应用程序的生命周期内将实现哪些接口。
  • 完成此操作后,在稍后的生命周期中,当任何代码需要接口实现时,它可以使用 Mvx.Resolve 方法来请求一个。

一种常见的模式是“构造函数注入”。

  • 我们的 TipViewModel 使用了这种模式。
  • 它呈现了一个构造函数,如下所示:public TipViewModel(ICalculation calculation)
  • 当应用程序运行时,MvvmCross 框架的一部分称为 ViewModelLocator ,用于查找和创建 ViewModels
  • 当需要 TipViewModel 时,ViewModelLocator 使用对 Mvx.IocConstruct 的调用来创建一个。
  • 这个 Mvx.IocConstruct 调用通过使用 Mvx.Resolve 找到的 ICalculation 实现来创建 TipViewModel

这显然只是一个非常简短的介绍。

如果您想了解更多信息,请查看互联网上一些出色的教程——就像这篇教程一样。

核心项目已完成 微笑 | <img src= " align="top" src="https://codeproject.org.cn/script/Forums/Images/smiley_smile.gif" />

我们来回顾一下我们遵循的步骤:

  1. 我们使用 Profile104 创建了一个新的 PCL 项目。
  2. 我们添加了对两个 PCL 库——CrossCore MvvmCross——的引用。
  3. 我们添加了一对 ICalculation 接口和实现。
  4. 我们添加了一个 TipViewModel,它:
    • 继承自 MvxViewModel
    • 使用了 ICalculation
    • 公开了许多 public 属性,每个属性都调用了 RaisePropertyChanged
  5. 我们添加了一个 App,它:
    • 继承自 MvxApplication
    • 注册了 ICalculation/Calculation 对。
    • IMvxAppStart 注册了一个特殊的启动对象。

这些是您为每个新的 MvvmCross 应用程序需要遵循的相同步骤。

继续

接下来,我们将开始研究如何为这个 MvvmCross 应用程序添加第一个 UI。

文章

历史 

  • 2013 年 3 月 22 日 - 首次提交  
© . All rights reserved.