翻译Rolling your own Mvvm for Xamarin.Forms

原文地址:http://www.michaelridland.com/xamarin/rolling-mvvm-xamarin-forms/

实现自己的Mvvm for Xamarin.Forms

更新:我已经采取了这个位置的最好的部分,并放入一个框架,这是一个超简单的Mvvm框架的Xamarin.Forms,它放在了github和nuget。
在这个博客中,我给出了一个如何在Xamarin.Forms中实现自己的Mvvm的例子。 这个Mvvm是基于约定的,在这种情况下,我使用了Page / PageModel命名,而不是Model / ViewModel命名,但是如果你喜欢,你可以将其改为View / ViewModel。 这个博客写的内容基于github上可用的示例应用程序。

本例中的约定。

  • 页面必须有一个相应的PageModel,命名重要,所以QuotePageModel必须有一个QuotePage
  • 一个页面可以有一个没有参数的Init方法
  • 页面可以有一个PageModel属性,它是视图模型
  • 页面上的BindingContext将自动设置为Model
  • 一个模型可以有一个接收一个对象的Init方法
  • 一个模型可以具有一个ReverseInit方法,它也可以使用一个对象,当一个模型被放在一个对象上时被调用

让我们看一个页面

public class QuotePage : ContentPage
{
    //按下时自动弹出
    public QuotePageModel PageModel { get; set; }

    public QuotePage ()
    {
    }

    //出现时自动执行
    public void Init()
    {
        Title = "Quote";
    }
}

和相应的PageModel

public class QuotePageModel : BasePageModel
{
    IDatabaseService _databaseService;
    public Quote Quote { get; set; }

    //数据库服务自动注入。
    public QuotePageModel (IDatabaseService databaseService)
    {
        _databaseService = databaseService;
    }

    //当Model出现的时候执行
    public void Init(object data)
    {
        Quote = data as Quote;
        if (Quote == null)
            Quote = new Quote ();
    }

    public Command Done
    {
        get {
            return new Command (() => {
                //This pops the current Page
                PopPageModel();
            });
        }
    }
}

Navigating Models

您可以使用PushPageModel方法和PopPageModel方法从视图模型中推送和弹出页面。

例如。PushPageModel(quote);

但在您可以做到这一点之前,您需要实现和注册一个IRootNavigation服务。 在我的情况下,我使用了一个ContainerPage并将其注册为NavigationHandler

//注册根导航

var containerPage = new RootContainerPage();
TinyIoC.TinyIoCContainer.Current.Register (containerPage);
public class RootContainerPage : MasterDetailPage, IRootNavigation
{
    ContentPage _menuPage;
    NavigationPage _contactNavPage, _quotesNavPage;

    public RootContainerPage ()
    {
        _contactNavPage = new NavigationPage (BasePageModel.ResolvePageModel (null));
        _quotesNavPage = new NavigationPage (BasePageModel.ResolvePageModel (null));
        Detail = _contactNavPage;

        _menuPage = new ContentPage ();
        _menuPage.Title = "Menu";
        var listView = new ListView();

        listView.ItemsSource = new string[] { "Contacts", "Quotes" };

        listView.ItemSelected += (sender, args) =>
        {
            if ((string)args.SelectedItem == "Contacts")
                Detail = _contactNavPage;
            if ((string)args.SelectedItem == "Quotes")
                Detail = _quotesNavPage;

            IsPresented = false;
        };

        _menuPage.Content = listView;
        Master = new NavigationPage(_menuPage) { Title = "Menu" };
    }

    public void PushPage (Page page, BasePageModel model)
    {
        ((NavigationPage)Detail).PushAsync (page);
    }

    public void PopPage ()
    {
        ((NavigationPage)Detail).PopAsync ();
    }
}

Implementing Property Changed

你会注意到我不需要实现属性更改事件,而是使用一个名为Fody / PropertyChanged的开源项目实现。 您可以从nuget安装。

控制反转/ TinyIOC

ViewPage构造函数的依赖将自动注入。 使用TinyIOC注册依赖项。

//注册数据库服务
TinyIoC.TinyIoCContainer.Current.Register ();

神奇的地方在哪里?

如果你想知道神奇的实现在哪里发生,那么看看示例应用程序中的BasePageModel.cs。

平台依赖关系

此应用程序利用SQLite的平台依赖关系。

单元测试

如果我们遵循惯例,那么模型是松耦合的,容易测试。

您可以将模拟的依赖关系传递给模型并进行测试。 在这里看到一个例子:

[TestFixture]
public class ContactPageModelTests
{
    [Test]
    public static void CreateNewContact()
    {
        var container = A.Fake ();
        TinyIoC.TinyIoCContainer.Current.Register (container);

        var db = new DatabaseService (new SQLiteFactory());
        var vm = new ContactPageModel (db);
        vm.Init (null);

        //保存到数据库
        vm.Contact.Name = "Peter";
        vm.Contact.Phone = "9087";
        vm.Done.Execute (null);

        Assert.IsTrue (vm.Contact.ContactId > 0);

        //从数据库取出
        var savedContact 
                = db.Conn.Table ().Where ((c) => c.ContactId == vm.Contact.ContactId).FirstOrDefault ();

        Assert.AreEqual ("Peter", savedContact.Name);
        Assert.AreEqual ("9087", savedContact.Phone);
        A.CallTo (() => container.PopPage ()).MustHaveHappened ();
    }
}

请去看看github上的代码。

https://github.com/rid00z/XamarinFormsQuoteApp

Thanks

Michael

你可能感兴趣的:(翻译Rolling your own Mvvm for Xamarin.Forms)