翻譯Rolling your own Mvvm for Xamarin.Forms

原文地址: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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末漫试,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子碘赖,更是在濱河造成了極大的恐慌驾荣,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件普泡,死亡現(xiàn)場(chǎng)離奇詭異播掷,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)撼班,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)歧匈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人砰嘁,你說(shuō)我怎么就攤上這事件炉。” “怎么了般码?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)板祝。 經(jīng)常有香客問(wèn)我宫静,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任孤里,我火速辦了婚禮伏伯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捌袜。我一直安慰自己说搅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布虏等。 她就那樣靜靜地躺著弄唧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪霍衫。 梳的紋絲不亂的頭發(fā)上候引,一...
    開(kāi)封第一講書(shū)人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音敦跌,去河邊找鬼澄干。 笑死,一個(gè)胖子當(dāng)著我的面吹牛柠傍,可吹牛的內(nèi)容都是我干的麸俘。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼惧笛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼从媚!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起徐紧,我...
    開(kāi)封第一講書(shū)人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤静檬,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后并级,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體拂檩,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年嘲碧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了稻励。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡愈涩,死狀恐怖望抽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情履婉,我是刑警寧澤煤篙,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站毁腿,受9級(jí)特大地震影響辑奈,放射性物質(zhì)發(fā)生泄漏苛茂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一鸠窗、第九天 我趴在偏房一處隱蔽的房頂上張望妓羊。 院中可真熱鬧,春花似錦稍计、人聲如沸躁绸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)净刮。三九已至,卻和暖如春茧球,著一層夾襖步出監(jiān)牢的瞬間庭瑰,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工抢埋, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人督暂。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓揪垄,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親逻翁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子饥努,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容