Art*_*ter 10 xamarin.ios xamarin.android windows-phone mvvmcross windows-store-apps
我试图了解ViewModels和Service类的实例化,并将其写入其他人.请在需要的地方更正/添加.
ViewModels和Services的实例化不是以最常见的方式完成的.它是用反射完成的.
在TipCalc中你有:
public class FirstViewModel : MvxViewModel
{
    private readonly ICalculationService _calculationService;
    public FirstViewModel(ICalculationService calculationService)
    {
        _calculationService = calculationService;
    }
...
}
和
public class App : Cirrious.MvvmCross.ViewModels.MvxApplication
{
    public override void Initialize()
    {
        CreatableTypes()
         .EndingWith("Service")
         .AsInterfaces()
         .RegisterAsLazySingleton();
    ...
    }
}
在Initialize()期间,设计为Service的接口和类(名称以Service结尾)使用反射以及接口名称和类名称(IPersonService和PersonService)进行配对.这稍后用于反向查找类的实例(查找表包含对服务类的单例实例的延迟引用.服务在null时创建.
public FirstViewModel(ICalculationService calculationService)引用CalculationService的实例.这是通过使用先前创建的查找表来完成的.
ViewModels的实例化是通过Mvx框架完成的.当"询问"MvxFramework实例化的ViewModel时,它将反映ViewModel并确定该类上的构造函数.如果有一个无参数构造函数,那么将使用它.如果存在带参数的构造函数且参数是服务类的接口,则该服务的(单例)实例将用作参数.
服务以类似的方式实例化; 他们的构造函数反映和参数实例化(单例).等等.
Stu*_*art 62
这里使用的想法是:
这里有很多文章和介绍 - 一些很好的起点是Martin Fowler的介绍和Joel Abrahamsson的IoC介绍.我还制作了一些动画幻灯片作为一个简单的演示.
特别是在MvvmCross中,我们提供了一个静态类Mvx,它作为注册和解析接口及其实现的单一位置.
MvvmCross Service Location的核心思想是你可以编写类和接口,如:
public interface IFoo
{
    string Request();
}
public class Foo : IFoo
{
    public string Request()
    {
        return "Hello World";
    }
}
编写这一对后,您可以将Foo实例注册为单例,实现IFoo使用:
// every time someone needs an IFoo they will get the same one
Mvx.RegisterSingleton<IFoo>(new Foo());
如果你这样做,那么任何代码都可以调用:
    var foo = Mvx.Resolve<IFoo>();
并且每次调用都会返回相同的Foo 实例.
作为对此的变体,您可以注册一个懒惰的单身人士.这是写的
// every time someone needs an IFoo they will get the same one
// but we don't create it until someone asks for it
Mvx.RegisterSingleton<IFoo>(() => new Foo());
在这种情况下:
Foo在最初创建Mvx.Resolve<IFoo>()一个新代码Foo最后一个选择是,你可以注册IFoo和Foo配对:
// every time someone needs an IFoo they will get a new one
Mvx.RegisterType<IFoo, Foo>();
在这种情况下,每次调用Mvx.Resolve<IFoo>()都会创建一个新的Foo- 每个调用都会返回一个不同的调用Foo.
如果您创建了几个接口实现并将它们全部注册:
Mvx.RegisterType<IFoo, Foo1>();
Mvx.RegisterSingleton<IFoo>(new Foo2());
Mvx.RegisterType<IFoo, Foo3>();
然后每次调用都会替换以前的注册 - 因此当客户端调用时,Mvx.Resolve<IFoo>()将返回最近的注册.
这可用于:
IUserInfo使用真实实现替换空实现.MvvmCross的默认NuGet模板在核心中包含一段代码,App.cs如:
CreatableTypes()
    .EndingWith("Service")
    .AsInterfaces()
    .RegisterAsLazySingleton();
此代码使用Reflection来:
creatable- 即:
abstract技术说明:懒惰的单身执行这里是相当的技术-它可以确保如果一个类实现IOne和ITwo再同一个实例解析时都返回IOne和ITwo.
在这里结束的名称选择Service- 以及使用懒惰单身人士的选择只是个人惯例.如果您希望为对象使用其他名称或其他生命周期,则可以使用其他调用或多次调用替换此代码,例如:
CreatableTypes()
    .EndingWith("SingleFeed")
    .AsInterfaces()
    .RegisterAsLazySingleton();
CreatableTypes()
    .EndingWith("Generator")
    .AsInterfaces()
    .RegisterAsDynamic();
CreatableTypes()
    .EndingWith("QuickSand")
    .AsInterfaces()
    .RegisterAsSingleton();
Linq如果您愿意,您还可以使用其他帮助方法来帮助进一步定义您的注册 - 例如Inherits,Except.WithAttribute,Containing,InNamespace...如
        CreatableTypes()
            .StartingWith("JDI")
            .InNamespace("MyApp.Core.HyperSpace")
            .WithAttribute(typeof(MySpecialAttribute))
            .AsInterfaces()
            .RegisterAsSingleton();
当然,您也可以在核心以外的程序集上使用相同类型的注册逻辑 - 例如:
typeof(Reusable.Helpers.MyHelper).Assembly.CreatableTypes()
    .EndingWith("Helper")
    .AsInterfaces()
    .RegisterAsDynamic();
或者,如果您不想使用此基于反射的注册,那么您只需手动注册您的实现:
Mvx.RegisterSingleton<IMixer>(new MyMixer());
Mvx.RegisterSingleton<ICheese>(new MyCheese());
Mvx.RegisterType<IBeer, Beer>();
Mvx.RegisterType<IWine, Wine>();
选择权归你的.
同样Mvx.Resolve<T>,Mvx静态类提供了一种基于反射的机制,可在对象构造期间自动解析参数.
例如,如果我们添加一个类,如:
public class Bar
{
    public Bar(IFoo foo)
    {
        // do stuff
    }
}
然后您可以使用以下命令创建此对象
    Mvx.IocConstruct<Bar>();
这次通话期间会发生什么:
BarIFooMvx.Resolve<IFoo>()获取已注册的实现IFooIFoo参数调用构造函数在创建ViewModel时,此"构造函数注入"机制在MvvmCross内部使用.
如果您声明一个ViewModel:
 public class MyViewModel : MvxViewModel
 {
     public MyViewModel(IMvxJsonConverter jsonConverter, IMvxGeoLocationWatcher locationWatcher)
     {
        // ....
     }
 }
然后MvvmCross将使用Mvx静态类来解决的对象为jsonConverter和locationWatcher一个时MyViewModel被创建.
这很重要,因为:
locationWatcher在不同平台上轻松提供不同的课程(在iPhone上您可以使用与之交谈的观察者CoreLocation,在Windows Phone上您可以使用与之交谈的观察者System.Device.LocationJson.NetJson 的实现,则可以使用ServiceStack.Text实现.在内部,该Mvx.Resolve<T>机制在需要新对象时使用构造函数注入.
这使您可以注册依赖于其他接口的实现,例如:
public interface ITaxCalculator
{
    double TaxDueFor(int customerId)
}
public class TaxCalculator
{
    public TaxCalculator(ICustomerRepository customerRepository, IForeignExchange foreignExchange, ITaxRuleList taxRuleList)
    {
    // code...
    }
    // code...
}
如果您将此计算器注册为:
Mvx.RegisterType<ITaxCalculator, TaxCalculator>();
然后,当客户端调用Mvx.Resolve<ITaxCalculator>()然后MvvmCross将创建一个新TaxCalculator的实例,解决所有的ICustomerRepository,IForeignExchange而ITaxRuleList在操作过程中.
此外,此过程是递归的 - 因此,如果这些返回的对象中的任何一个需要另一个对象 - 例如,如果您的IForeignExchange实现需要一个IChargeCommission对象 - 那么MvvmCross也将为您提供Resolve.
有时您需要在ViewModel中使用某些特定于平台的功能.例如,您可能希望在ViewModel中获取当前屏幕尺寸 - 但是没有现成的便携式.Net调用来执行此操作.
当您想要包含这样的功能时,有两个主要选择:
在您的核心项目中,您可以声明一个接口,您可以在您的类中使用该接口 - 例如:
public interface IScreenSize
{
    double Height { get; }
    double Width { get; }
}
public class MyViewModel : MvxViewModel
{
    private readonly IScreenSize _screenSize;
    public MyViewModel(IScreenSize screenSize)
    {
         _screenSize = screenSize;
    }
    public double Ratio
    {
        get { return (_screenSize.Width / _screenSize.Height); }
    }
}
在每个UI项目中,您可以为其声明特定于平台的实现IScreenSize.一个简单的例子是:
public class WindowsPhoneScreenSize : IScreenSize
{
    public double Height { get { return 800.0; } }
    public double Width { get { return 480.0; } }
}
然后,您可以在每个特定平台的安装文件的注册这些实现-例如,你可以覆盖MvxSetup.InitializeFirstChance与
protected override void InitializeFirstChance()
{
    Mvx.RegisterSingleton<IScreenSize>(new WindowsPhoneScreenSize());
    base.InitializeFirstChance();
}
完成此操作后,MyViewModel将IScreenSize在每个平台上提供正确的特定于平台的实现.
甲插件是用于组合PCL组件的MvvmCross图案,加上任选以打包某些功能的一些特定于平台的组件.
这个插件层只是一个模式 - 一些简单的约定 - 用于命名相关的程序集,包括小型PluginLoader和Plugin辅助类,以及使用IoC.通过这种模式,它可以轻松地跨平台和跨应用程序包含,重用和测试功能.
例如,现有插件包括:
System.IO对操作文件的类型方法的访问SQLite-net对所有平台的访问.如果您想了解如何在您的应用程序中使用这些插件,那么:
编写插件很容易,但起初可能会感到有些畏惧.
关键步骤是:
为插件创建主PCL程序集 - 这应该包括:
PluginLoaderMvvmCross将用于启动插件的特殊类(可选)创建特定于平台的程序集:
PluginMvvmCross将用于启动此特定于平台的扩展的特殊类可选择提供文档和NuGet打包等附加功能,使插件更易于重用.
我不打算在这里详细介绍插件.
如果您想了解更多关于编写自己的插件的信息,那么:
Vibrate在https://github.com/slodge/MvvmCross-Tutorials/tree/master/GoodVibrations创建一个插件 如果您不想在代码中使用它,那么请不要.
只需CreatableTypes()...从App.cs中删除代码,然后在ViewModels中使用"普通代码" - 例如:
public class MyViewModel : MvxViewModel
{
    private readonly ITaxService _taxService;
    public MyViewModel()
    {
        _taxService = new TaxService();
    }
}
那里有很多优秀的库,包括AutoFac,Funq,MEF,OpenNetCF,TinyIoC以及许多其他库!
如果要替换MvvmCross实现,则需要:
Adapter层来提供他们的服务位置代码IMvxIoCProviderCreateIocProvider在您的Setup类中覆盖以提供此替代IMvxIoCProvider实现.或者,您可以组织混合情况 - 两个IoC/ServiceLocation系统并排存在.
提供了IoC的Property Injection实现示例.
这可以使用Setup覆盖来初始化:
protected override IMvxIoCProvider CreateIocProvider()
{
    return MvxPropertyInjectingIoCContainer.Initialise();
}
MvvmCross中的IoC容器设计得非常轻巧,并且针对我构建的移动应用程序所需的功能级别.
如果您需要更高级/复杂的功能,那么您可能需要使用不同的提供程序或不同的方法 - 对此的一些建议将在以下内容中讨论:MvvmCross IoC中的子容器
| 归档时间: | 
 | 
| 查看次数: | 5214 次 | 
| 最近记录: |