Xamarin Forms MvvM框架之FreshMvvM翻譯一

原文地址:https://github.com/rid00z/FreshMvvm

FreshMvvm for Xamarin.Forms

FreshMvvm是專門為Xamarin.Forms設(shè)計(jì)的輕量Mvvm框架埃疫。 它是簡單和靈活的绕娘。

與其他的選擇相比怎么樣?

  • 輕量,超簡單
  • 它專為Xamarin.Forms設(shè)計(jì)
  • 設(shè)計(jì)易于學(xué)習(xí)和開發(fā)(當(dāng)你還沒有準(zhǔn)備好RxUI時(shí)它是很好的)
  • 使用比配置更好的設(shè)定。

特點(diǎn)

  • PageModel到PageModel導(dǎo)航
  • BindingContext的自動(dòng)構(gòu)造
  • 頁面事件的自動(dòng)構(gòu)造(例如頁面出現(xiàn))
  • PageModel上的基本方法(允許傳值)(init,reverseinit)
  • 內(nèi)置IOC容器(依賴注入)
  • PageModel構(gòu)造函數(shù)注入
  • Basic中提供的基本方法,如彈消息框
  • 內(nèi)置導(dǎo)航類型為SimpleNavigation,Tabbed和MasterDetail

它的故事

當(dāng)Xamarin.Forms發(fā)布時(shí)蜕窿,我(Michael Ridland)是Xamarin傳統(tǒng)應(yīng)用程序的一部分谋逻。 我想將項(xiàng)目移到Xamarin.Forms上,但是在該項(xiàng)目中我使用的是MvvMCross桐经。 當(dāng)時(shí)MvvmCross不支持Xamarin.Forms毁兆,所以我有幾個(gè)選擇

  • (1)適應(yīng)MvvmCross
  • (2)找到一個(gè)替代的框架
  • (3)實(shí)現(xiàn)我自己的MvvM。

關(guān)于MvvmCross的最好的部分是它是雙向數(shù)據(jù)綁定到原生的iOS / Android控件阴挣,但由于Xamarin.Forms已經(jīng)擁有Databinding內(nèi)置气堕,這是沒有用的,MvvMCross太大了畔咧,我不需要這么大茎芭。
我也無法找到一個(gè)可以輕松移動(dòng)的替代方案。所以我做了屬于我自己簡單并且靈活MvvM框架誓沸。

它是從這個(gè)帖子開始的——翻譯在這梅桩,為Xamarin.Forms實(shí)現(xiàn)自己的Mvvm。 我盡量為自己的MvvM框架做得簡單拜隧。

從來沒有想過來寫一個(gè)框架宿百,但在幾次發(fā)布Mvvm解決方案之后,我發(fā)現(xiàn)很多人都想要它洪添,并且似乎對此感興趣垦页。 另外考慮到我從Xamarin.Forms開始就在我所有的項(xiàng)目中使用了這個(gè)框架,我知道它的工作原理干奢,所以我創(chuàng)建了FreshMvvm痊焊,于是它誕生了。

共同遵守的設(shè)定

  • 一個(gè)頁面必須有一個(gè)相應(yīng)的PageModel律胀,類的命名十分重要宋光,所以QuotePageModel必須有一個(gè)QuotePage頁面貌矿。QuotePage上的BindingContext將被自動(dòng)設(shè)置為Model
  • 一個(gè)PageModel可以擁有一個(gè)接收一個(gè)對象的Init方法
  • 一個(gè)PageModel可以有一個(gè)ReverseInit方法炭菌,它也可以使用一個(gè)對象,當(dāng)一個(gè)模型被一個(gè)對象引用時(shí)被調(diào)用
  • PageModel可以將依賴關(guān)系自動(dòng)注入到構(gòu)造函數(shù)中

導(dǎo)航

FreshMvvm中的主要導(dǎo)航形式是PageModel到PageModel逛漫,這實(shí)際上意味著我們的觀點(diǎn)不了解導(dǎo)航黑低。

  • 所以要在PageModels之間導(dǎo)航使用:
await CoreMethods.PushPageModel<QuotePageModel>(); // 推送導(dǎo)航堆棧
await CoreMethods.PushPageModel<QuotePageModel>(null, true); // 推送模態(tài)
  • FreshMvvm中的導(dǎo)航引擎是通過一個(gè)簡單的界面完成的,其中包含了Push和Pop的方法酌毡。 基本上這些方法可以以任何他們喜歡的方式控制應(yīng)用程序的導(dǎo)航克握。
public interface IFreshNavigationService
{
   Task PushPage(Page page, FreshBasePageModel model, bool modal = false);
   Task PopPage(bool modal = false);
}
  • 在PushPage和PopPage中,您可以執(zhí)行任何您喜歡的導(dǎo)航枷踏,這可以從簡單的導(dǎo)航到高級嵌套導(dǎo)航菩暗。

該框架包含一些內(nèi)置的導(dǎo)航容器,用于不同類型的導(dǎo)航旭蠕。

  • 基本導(dǎo)航 - 內(nèi)置

var page = FreshPageModelResolver.ResolvePageModel<MainMenuPageModel> ();
var basicNavContainer = new FreshNavigationContainer (page);
MainPage = basicNavContainer;
  • 主要細(xì)節(jié) - 內(nèi)置

var masterDetailNav = new FreshMasterDetailNavigationContainer ();
masterDetailNav.Init ("Menu");
masterDetailNav.AddPage<ContactListPageModel> ("Contacts", null);
masterDetailNav.AddPage<QuoteListPageModel> ("Pages", null);
MainPage = masterDetailNav;
  • 標(biāo)簽導(dǎo)航 - 內(nèi)置

var tabbedNavigation = new FreshTabbedNavigationContainer ();
tabbedNavigation.AddTab<ContactListPageModel> ("Contacts", null);
tabbedNavigation.AddTab<QuoteListPageModel> ("Pages", null);
MainPage = tabbedNavigation;
  • 實(shí)施自定義導(dǎo)航

可以通過實(shí)現(xiàn)IFreshNavigationService.來設(shè)置任何類型的導(dǎo)航停团。在示例應(yīng)用程序中有一個(gè)示例旷坦,名為CustomImplementedNav.cs。

示例應(yīng)用程序

  • 基本導(dǎo)航例子
  • 標(biāo)簽式導(dǎo)航例子
  • MasterDetail導(dǎo)航例子
  • 使用MasterDetail Popover示例的Tabbed導(dǎo)航(這在Sample App中被稱為CustomImplementedNav)

控制反轉(zhuǎn)(IOC)

所以你不需要使用你自己的IOC容器佑稠,F(xiàn)reshMvvm自帶了一個(gè)內(nèi)置的IOC容器秒梅,它使用的是TinyIOC,但使用不同的命名來避免沖突舌胶。要在容器中注冊服務(wù)注冊:

FreshIOC.Container.Register<IDatabaseService, DatabaseService>();

注入時(shí)使用:

FreshIOC.Container.Resolve<IDatabaseService>();

這也是驅(qū)動(dòng)構(gòu)建器注入的方式捆蜀。

我們現(xiàn)在流暢支持API來設(shè)置對象在IOC容器內(nèi)的生命周期。

// 默認(rèn)情況下幔嫂,我們將具體類型注冊為多例辆它,并將接口注冊為單例
FreshIOC.Container.Register<MyConcreteType>(); // 多例
FreshIOC.Container.Register<IMyInterface, MyConcreteType>(); // 單例

// Fluent API允許我們改變這種行為
FreshIOC.Container.Register<MyConcreteType>().AsSingleton(); // 單例
FreshIOC.Container.Register<IMyInterface, MyConcreteType>().AsMultiInstance(); // 多例

如下所示,IFreshIOC接口方法返回IRegisterOptions接口婉烟。

public interface IFreshIOC
{
    object Resolve(Type resolveType);
    IRegisterOptions Register<RegisterType>(RegisterType instance) where RegisterType : class;
    IRegisterOptions Register<RegisterType>(RegisterType instance, string name) where RegisterType : class;
    ResolveType Resolve<ResolveType>() where ResolveType : class;
    ResolveType Resolve<ResolveType>(string name) where ResolveType : class;
    IRegisterOptions Register<RegisterType, RegisterImplementation> ()  where RegisterType : class  where RegisterImplementation : class, RegisterType;
}

從register方法返回的接口是IRegisterOptions娩井。

public interface IRegisterOptions
{
    IRegisterOptions AsSingleton();
    IRegisterOptions AsMultiInstance();
    IRegisterOptions WithWeakReference();
    IRegisterOptions WithStrongReference();
    IRegisterOptions UsingConstructor<RegisterType>(Expression<Func<RegisterType>> constructor);
}

PageModel - 構(gòu)造函數(shù)注入

當(dāng)PageModels被推送到IOC容器中的services可以被推入構(gòu)造函數(shù)。

FreshIOC.Container.Register<IDatabaseService, DatabaseService>();

PageModel重要方法

/// <summary>
/// 以前的頁面模型似袁,這是自動(dòng)推送填充
/// </summary>
public FreshBasePageModel PreviousPageModel { get; set; }
/// <summary>
/// 對當(dāng)前頁面的引用洞辣,即自動(dòng)推送填充
/// </summary>
public Page CurrentPage { get; set; }
/// <summary>
/// 核心方法是應(yīng)用程序的基本內(nèi)置方法,包括推送昙衅,彈出和彈消息框
/// </summary>
public IPageModelCoreMethods CoreMethods { get; set; }    
/// <summary>
/// 當(dāng)一個(gè)頁面調(diào)用Pop'd這個(gè)方法時(shí)扬霜,它也允許返回?cái)?shù)據(jù)。
/// </summary>
/// <param name="returndData">從...返回的數(shù)據(jù) </param>
public virtual void ReverseInit(object returndData) { }
/// <summary>
/// 在加載PageModel時(shí)調(diào)用此方法而涉,initData是之前從pagemodel發(fā)送來的數(shù)據(jù)
/// </summary>
/// <param name="initData">從推送器發(fā)送到此PageModel的數(shù)據(jù)</param>
public virtual void Init(object initData) { }
/// <summary>
/// View消失時(shí)調(diào)用此方法著瓶。
/// </summary>
protected virtual void ViewIsDisappearing (object sender, EventArgs e)
{
}
/// <summary>
/// View出現(xiàn)時(shí)調(diào)用此方法
/// </summary>
protected virtual void ViewIsAppearing (object sender, EventArgs e)
{
}

核心方法

每個(gè)PageModel都有一個(gè)名為“CoreMethods”的屬性,當(dāng)一個(gè)PageModel被推送時(shí)啼县,它被自動(dòng)填充材原,它是大多數(shù)應(yīng)用程序需要的基本功能,如彈消息框季眷,推送余蟹,彈出等。

public interface IPageModelCoreMethods
{
    Task DisplayAlert (string title, string message, string cancel);
    Task<string> DisplayActionSheet (string title, string cancel, string destruction, params string[] buttons);
    Task<bool> DisplayAlert (string title, string message, string accept, string cancel);
    Task PushPageModel<T>(object data, bool modal = false) where T : FreshBasePageModel;
    Task PopPageModel(bool modal = false);
    Task PopPageModel(object data, bool modal = false);
    Task PushPageModel<T>() where T : FreshBasePageModel;
}

Page的重要方法

PageModel Init PropertyChanged

示例PageModel

[ImplementPropertyChanged] // 使用Fody for Property更改通知
public class QuoteListPageModel : FreshBasePageModel
{
    IDatabaseService _databaseService;
    
    //這些通過構(gòu)造函數(shù)注入IOC
    public QuoteListPageModel (IDatabaseService databaseService) 
    {
        _databaseService = databaseService;
    }
    
    public ObservableCollection<Quote> Quotes { get; set; }
    
    public override void Init (object initData)
    {
        Quotes = new ObservableCollection<Quote> (_databaseService.GetQuotes ());
    }
    
    //框架支持標(biāo)準(zhǔn)View出現(xiàn)和消失事件
    protected override void ViewIsAppearing (object sender, System.EventArgs e)
    {
        CoreMethods.DisplayAlert ("Page is appearing", "", "Ok");
        base.ViewIsAppearing (sender, e);
    }
    
    protected override void ViewIsDisappearing (object sender, System.EventArgs e)
    {
        base.ViewIsDisappearing (sender, e);
    }

    //跳轉(zhuǎn)到另一個(gè)頁面后子刮,如果返回此頁面調(diào)用
    public override void ReverseInit (object value)
    {
        var newContact = value as Quote;
        if (!Quotes.Contains (newContact))
        {
            Quotes.Add (newContact);
        }
    }

    public Command AddQuote 
    {
        get 
        {
            return new Command (async () => 
            {
                //Push A Page Model
                await CoreMethods.PushPageModel<QuotePageModel> ();
            });
        }
    }

    Quote _selectedQuote;

    public Quote SelectedQuote 
    {
        get 
        {
            return _selectedQuote;
        }
        set 
        {
            _selectedQuote = value;
            if (value != null)
                QuoteSelected.Execute (value);
        }
    }

    public Command<Quote> QuoteSelected 
    {
        get 
        {
            return new Command<Quote> (async (quote) => 
            {
                await CoreMethods.PushPageModel<QuotePageModel> (quote);
            });
        }
    }
}

多個(gè)導(dǎo)航服務(wù)

在FreshMvvm中可以進(jìn)行任何類型的導(dǎo)航威酒,通過實(shí)現(xiàn)自定義導(dǎo)航服務(wù)來完成自定義或高級場景。即使有這種能力挺峡,發(fā)現(xiàn)在FreshMvvm中做高級導(dǎo)航方案有點(diǎn)困難葵孤。在我回顧了FreshMvvm的所有支持問題之后,我發(fā)現(xiàn)人們的基本問題是他們希望能夠多次使用我們內(nèi)置的導(dǎo)航容器橱赠,其中兩個(gè)主要例子是

  • (1)具有導(dǎo)航堆棧的主要細(xì)節(jié):在一個(gè)master和另一個(gè)master的細(xì)節(jié)
  • (2)使用新的推動(dòng)導(dǎo)航容器模型的能力尤仍。

為了支持這兩種情況,我得出結(jié)論狭姨,F(xiàn)reshMvvm需要具有命名NavigationServices的能力宰啦,以便我們可以支持多個(gè)NavigationService鲤嫡。

使用多個(gè)導(dǎo)航容器

在下面我們運(yùn)行一個(gè)單一的主細(xì)節(jié)的兩個(gè)導(dǎo)航堆棧。

var masterDetailsMultiple = new MasterDetailPage (); //generic master detail page

//我們使用ContactList設(shè)置第一個(gè)導(dǎo)航容器
var contactListPage = FreshPageModelResolver.ResolvePageModel<ContactListPageModel> ();
contactListPage.Title = "Contact List";
//我們設(shè)置名為MasterPageArea的第一個(gè)導(dǎo)航容器
var masterPageArea = new FreshNavigationContainer (contactListPage, "MasterPageArea");
masterPageArea.Title = "Menu";

masterDetailsMultiple.Master = masterPageArea; //將第一個(gè)導(dǎo)航容器設(shè)置為Master

//我們使用QuoteList設(shè)置第二個(gè)導(dǎo)航容器
var quoteListPage = FreshPageModelResolver.ResolvePageModel<QuoteListPageModel> ();
quoteListPage.Title = "Quote List";
//我們設(shè)置名為DetailPageArea的第二個(gè)導(dǎo)航容器
var detailPageArea = new FreshNavigationContainer (quoteListPage, "DetailPageArea");

masterDetailsMultiple.Detail = detailPageArea; //將第二個(gè)導(dǎo)航容器設(shè)置為“Detail”

MainPage = masterDetailsMultiple;

在新的導(dǎo)航堆棧使用PushModally

//push a basic page Modally
var page = FreshPageModelResolver.ResolvePageModel<MainMenuPageModel> ();
var basicNavContainer = new FreshNavigationContainer (page, "secondNavPage");
await CoreMethods.PushNewNavigationServiceModal(basicNavContainer, new FreshBasePageModel[] { page.GetModel() }); 

//推送標(biāo)簽頁模型
var tabbedNavigation = new FreshTabbedNavigationContainer ("secondNavPage");
tabbedNavigation.AddTab<ContactListPageModel> ("Contacts", "contacts.png", null);
tabbedNavigation.AddTab<QuoteListPageModel> ("Quotes", "document.png", null);
await CoreMethods.PushNewNavigationServiceModal(tabbedNavigation);

//推送主細(xì)節(jié)頁面
var masterDetailNav = new FreshMasterDetailNavigationContainer ("secondNavPage");
masterDetailNav.Init ("Menu", "Menu.png");
masterDetailNav.AddPage<ContactListPageModel> ("Contacts", null);
masterDetailNav.AddPage<QuoteListPageModel> ("Quotes", null);
await CoreMethods.PushNewNavigationServiceModal(masterDetailNav);

在Xamarin.Forms MainPage上切換NavigationStacks

Xamarin.Forms中有些情況可能需要運(yùn)行多個(gè)導(dǎo)航堆棧绑莺。 一個(gè)很好的例子是當(dāng)你有一個(gè)用于認(rèn)證的導(dǎo)航堆棧和一個(gè)應(yīng)用程序主區(qū)域的堆棧暖眼。

首先我們可以為導(dǎo)航容器設(shè)置一些名稱。

public class NavigationContainerNames
{
    public const string AuthenticationContainer = "AuthenticationContainer";
    public const string MainContainer = "MainContainer";
}

然后我們可以創(chuàng)建我們的兩個(gè)導(dǎo)航容器并分配到主頁面纺裁。

var loginPage = FreshMvvm.FreshPageModelResolver.ResolvePageModel<LoginViewModel>();
var loginContainer = new FreshNavigationContainer(loginPage, NavigationContainerNames.AuthenticationContainer);

var myPitchListViewContainer = new MainTabbedPage(NavigationContainerNames.MainContainer);

MainPage = loginContainer;

一旦我們設(shè)置好了诫肠,我們現(xiàn)在可以切換我們的導(dǎo)航容器。

CoreMethods.SwitchOutRootNavigation(NavigationContainerNames.MainContainer);

自定義IOC容器

FreshMvvm 1.0的第二個(gè)主要要求是允許自定義IOC容器欺缘。 在您的應(yīng)用程序已經(jīng)具有要使用的容器的情況下栋豫。

使用自定義IOC容器非常簡單,因?yàn)槟恍枰獙?shí)現(xiàn)單個(gè)接口谚殊。

public interface IFreshIOC
{
    object Resolve(Type resolveType);
    void Register<RegisterType>(RegisterType instance) where RegisterType : class;
    void Register<RegisterType>(RegisterType instance, string name) where RegisterType : class;
    ResolveType Resolve<ResolveType>() where ResolveType : class;
    ResolveType Resolve<ResolveType>(string name) where ResolveType : class;
    void Register<RegisterType, RegisterImplementation> () where RegisterType : class where RegisterImplementation : class, RegisterType;

然后在系統(tǒng)中設(shè)置IOC容器丧鸯。

FreshIOC.OverrideContainer(myContainer);

相關(guān)視頻/快速入門指南

  • FreshMvvm n = 0 - Mvvm在Xamarin.Forms和為什么需要FreshMvvm
  • FreshMvvm n = 1:你的第一個(gè)FreshMvvm應(yīng)用程序
  • FreshMvvm n = 2 - IOC和構(gòu)造器注入
  • FreshMvvm n = 3:在FreshMvvm中導(dǎo)航
  • 在FreshMvvm中為Xamarin.Forms實(shí)現(xiàn)自定義導(dǎo)航
  • TDD在Xamarin Studio - Live Coding FreshMvvm
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市嫩絮,隨后出現(xiàn)的幾起案子丛肢,更是在濱河造成了極大的恐慌,老刑警劉巖剿干,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜂怎,死亡現(xiàn)場離奇詭異,居然都是意外死亡置尔,警方通過查閱死者的電腦和手機(jī)杠步,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來榜轿,“玉大人幽歼,你說我怎么就攤上這事∶危” “怎么了甸私?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長设褐。 經(jīng)常有香客問我颠蕴,道長泣刹,這世上最難降的妖魔是什么助析? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮椅您,結(jié)果婚禮上外冀,老公的妹妹穿的比我還像新娘。我一直安慰自己掀泳,他們只是感情好雪隧,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布西轩。 她就那樣靜靜地躺著,像睡著了一般脑沿。 火紅的嫁衣襯著肌膚如雪藕畔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天庄拇,我揣著相機(jī)與錄音注服,去河邊找鬼。 笑死措近,一個(gè)胖子當(dāng)著我的面吹牛溶弟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瞭郑,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼辜御,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了屈张?” 一聲冷哼從身側(cè)響起擒权,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎阁谆,沒想到半個(gè)月后菜拓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡笛厦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年纳鼎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裳凸。...
    茶點(diǎn)故事閱讀 40,615評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡贱鄙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出姨谷,到底是詐尸還是另有隱情逗宁,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布梦湘,位于F島的核電站瞎颗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏捌议。R本人自食惡果不足惜哼拔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瓣颅。 院中可真熱鬧倦逐,春花似錦、人聲如沸宫补。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至健民,卻和暖如春抒巢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背秉犹。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工虐秦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人凤优。 一個(gè)月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓悦陋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親筑辨。 傳聞我的和親對象是個(gè)殘疾皇子俺驶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評論 2 359

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,302評論 25 707
  • Awesome DotNet,這又是一個(gè) Awesome XXX 系列的資源整理棍辕,由 quozd 發(fā)起和維護(hù)暮现。內(nèi)容...
    小明yz閱讀 3,700評論 0 47
  • 原文地址:http://www.michaelridland.com/xamarin/rolling-mvvm-x...
    本大少_閱讀 431評論 0 0
  • 煩惱人生總嘆春, 紅花萬點(diǎn)落紅塵楚昭。 無聊作曲閑情寄栖袋, 多少哀傷那忍聞。 星影淡抚太, 月清痕塘幅, 凄風(fēng)冷雨打重門。 殘燈...
    仙女下凡塵閱讀 265評論 0 5
  • 這是從現(xiàn)在起尿贫,到2016年要完成的清單电媳。你要像個(gè)小孩一樣,有什么愿望就在睡覺前跟月亮說庆亡。然后第二天醒來自己去實(shí)現(xiàn)...
    Veromca5閱讀 552評論 0 4