原文地址:http://www.michaelridland.com/xamarin/rolling-mvvm-xamarin-forms/
實(shí)現(xiàn)自己的Mvvm for Xamarin.Forms
更新:我已經(jīng)采取了這個(gè)位置的最好的部分,并放入一個(gè)框架眨唬,這是一個(gè)超簡(jiǎn)單的Mvvm框架的Xamarin.Forms逝撬,它放在了github和nuget芥挣。
在這個(gè)博客中她君,我給出了一個(gè)如何在Xamarin.Forms中實(shí)現(xiàn)自己的Mvvm的例子萎胰。 這個(gè)Mvvm是基于約定的默辨,在這種情況下货岭,我使用了Page / PageModel命名,而不是Model / ViewModel命名徘禁,但是如果你喜歡诅诱,你可以將其改為View / ViewModel。 這個(gè)博客寫(xiě)的內(nèi)容基于github上可用的示例應(yīng)用程序送朱。
本例中的約定娘荡。
- 頁(yè)面必須有一個(gè)相應(yīng)的PageModel,命名重要驶沼,所以QuotePageModel必須有一個(gè)QuotePage
- 一個(gè)頁(yè)面可以有一個(gè)沒(méi)有參數(shù)的Init方法
- 頁(yè)面可以有一個(gè)PageModel屬性炮沐,它是視圖模型
- 頁(yè)面上的BindingContext將自動(dòng)設(shè)置為Model
- 一個(gè)模型可以有一個(gè)接收一個(gè)對(duì)象的Init方法
- 一個(gè)模型可以具有一個(gè)ReverseInit方法,它也可以使用一個(gè)對(duì)象回怜,當(dāng)一個(gè)模型被放在一個(gè)對(duì)象上時(shí)被調(diào)用
讓我們看一個(gè)頁(yè)面
public class QuotePage : ContentPage
{
//按下時(shí)自動(dòng)彈出
public QuotePageModel PageModel { get; set; }
public QuotePage ()
{
}
//出現(xiàn)時(shí)自動(dòng)執(zhí)行
public void Init()
{
Title = "Quote";
}
}
和相應(yīng)的PageModel
public class QuotePageModel : BasePageModel
{
IDatabaseService _databaseService;
public Quote Quote { get; set; }
//數(shù)據(jù)庫(kù)服務(wù)自動(dòng)注入大年。
public QuotePageModel (IDatabaseService databaseService)
{
_databaseService = databaseService;
}
//當(dāng)Model出現(xiàn)的時(shí)候執(zhí)行
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方法從視圖模型中推送和彈出頁(yè)面。
例如。PushPageModel<QuotePageModel>(quote);
但在您可以做到這一點(diǎn)之前翔试,您需要實(shí)現(xiàn)和注冊(cè)一個(gè)IRootNavigation服務(wù)轻要。 在我的情況下,我使用了一個(gè)ContainerPage并將其注冊(cè)為NavigationHandler
//注冊(cè)根導(dǎo)航
var containerPage = new RootContainerPage();
TinyIoC.TinyIoCContainer.Current.Register <IRootNavigation>(containerPage);
public class RootContainerPage : MasterDetailPage, IRootNavigation
{
ContentPage _menuPage;
NavigationPage _contactNavPage, _quotesNavPage;
public RootContainerPage ()
{
_contactNavPage = new NavigationPage (BasePageModel.ResolvePageModel<ContactsRootPageModel> (null));
_quotesNavPage = new NavigationPage (BasePageModel.ResolvePageModel<QuotesRootPageModel> (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
你會(huì)注意到我不需要實(shí)現(xiàn)屬性更改事件遏餐,而是使用一個(gè)名為Fody / PropertyChanged的開(kāi)源項(xiàng)目實(shí)現(xiàn)伦腐。 您可以從nuget安裝。
控制反轉(zhuǎn)/ TinyIOC
ViewPage構(gòu)造函數(shù)的依賴(lài)將自動(dòng)注入失都。 使用TinyIOC注冊(cè)依賴(lài)項(xiàng)。
//注冊(cè)數(shù)據(jù)庫(kù)服務(wù)
TinyIoC.TinyIoCContainer.Current.Register <IDatabaseService幸冻,DatabaseService>();
神奇的地方在哪里粹庞?
如果你想知道神奇的實(shí)現(xiàn)在哪里發(fā)生,那么看看示例應(yīng)用程序中的BasePageModel.cs洽损。
平臺(tái)依賴(lài)關(guān)系
此應(yīng)用程序利用SQLite的平臺(tái)依賴(lài)關(guān)系庞溜。
單元測(cè)試
如果我們遵循慣例,那么模型是松耦合的碑定,容易測(cè)試流码。
您可以將模擬的依賴(lài)關(guān)系傳遞給模型并進(jìn)行測(cè)試。 在這里看到一個(gè)例子:
[TestFixture]
public class ContactPageModelTests
{
[Test]
public static void CreateNewContact()
{
var container = A.Fake<IRootNavigation> ();
TinyIoC.TinyIoCContainer.Current.Register<IRootNavigation> (container);
var db = new DatabaseService (new SQLiteFactory());
var vm = new ContactPageModel (db);
vm.Init (null);
//保存到數(shù)據(jù)庫(kù)
vm.Contact.Name = "Peter";
vm.Contact.Phone = "9087";
vm.Done.Execute (null);
Assert.IsTrue (vm.Contact.ContactId > 0);
//從數(shù)據(jù)庫(kù)取出
var savedContact
= db.Conn.Table<Contact> ().Where ((c) => c.ContactId == vm.Contact.ContactId).FirstOrDefault ();
Assert.AreEqual ("Peter", savedContact.Name);
Assert.AreEqual ("9087", savedContact.Phone);
A.CallTo (() => container.PopPage ()).MustHaveHappened ();
}
}
請(qǐng)去看看github上的代碼延刘。
https://github.com/rid00z/XamarinFormsQuoteApp
Thanks
Michael