Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

FreshMvvm is a super light Mvvm Framework designed specifically for Xamarin.Forms. It's designed to be Easy, Simple and Flexible.

License

NotificationsYou must be signed in to change notification settings

rid00z/FreshMvvm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

If you're looking for .NET MAUI version of FreshMvvm, aka FreshMvvm.Maui then please visit:https://github.com/XAM-Consulting/FreshMvvm.Maui

FreshMvvm for Xamarin.Forms

FreshMvvm is a super light Mvvm Framework designed specifically for Xamarin.Forms. It's designed to be Easy, Simple and Flexible.

How does it compare to other options?

  • It's super light and super simple
  • It's specifically designed for Xamarin.Forms
  • Designed to be easy to learn and develop (great when you are not ready for RxUI)
  • Uses a Convention over Configuration

Features

  • PageModel to PageModel Navigation
  • Automatic wiring of BindingContext
  • Automatic wiring of Page events (eg. appearing)
  • Basic methods (with values) on PageModel (init, reverseinit)
  • Built in IOC Container
  • PageModel Constructor Injection
  • Basic methods available in Model, like Alert
  • Built in Navigation types for SimpleNavigation, Tabbed and MasterDetail

NoteDifferent to standard naming conventions, FreshMvvm uses Page and PageModel instead of View and ViewModel, this is inline with Xamarin.Forms using Pages Now we can use both the ViewModel naming conventions.

The Story

I(Michael Ridland) was part-way into a Xamarin Traditional application when Xamarin.Forms was released. I wanted to move the project onto Xamarin.Forms but on that project I was using MvvmCross. At that time MvvmCross had no support for Xamarin.Forms, so I had the option of 1) adapting MvvmCross, 2) finding an alternative or 3) rolling my own Mvvm. The best part about MvvmCross was it's two-way databinding to the native iOS/Android controls but since Xamarin.Forms already had the Databinding builtin, that wasn't useful and the size with MvvmCross was an overhead when I didn't require it. I also wasn't able to find an alternative that I could easily move to. So that I could keep it simple and flexible, I ended up rolling my own Mvvm.

It's grown up from this post onrolling your own Mvvm for Xamarin.Forms. I try hard to keep the simplicity of rolling your own Mvvm for Xamarin.Forms.

It was never a plan to create a framework but after presenting my Mvvm solution at a few events, I found many people wanted it and seemed to be really interested in it. Also considering I've been using this Framework in all my projects from the start of Xamarin.Forms I know that it works, so I created FreshMvvm and that's how it was born.

Conventions

This Framework, while simple, is also powerful and uses a Convention over Configuration style.

NoteDifferent to standard naming conventions, FreshMvvm uses Page and PageModel instead of View and ViewModel, this is inline with Xamarin.Forms using Pages Now we can use both the ViewModel naming conventions.

  • A Page must have a corresponding PageModel, with naming important so a QuotePageModel must have a QuotePageThe BindingContext on the page will be automatically set with the Model
  • A PageModel can have a Init method that takes a object
  • A PageModel can have a ReverseInit method that also take a object and is called when a model is poped with a object
  • PageModel can have dependancies automatically injected into the Constructor

Navigation

The Primary form of Navigation in FreshMvvm is PageModel to PageModel, this essentially means our views have no idea of Navigation.

So to Navigate between PageModels use:

awaitCoreMethods.PushPageModel<QuotePageModel>();// Pushes navigation stackawaitCoreMethods.PushPageModel<QuotePageModel>(null,true);// Pushes a ModalawaitCoreMethods.PushPageModel<QuotePageModel>(pm=>pm.Quote="Quote 23")// Pushes Navigation Stack and initializes the property 'Quote' with  value 'Quote 23'

The engine for Navigation in FreshMvvm is done via a simple interface, with methods for Push and Pop. Essentially these methods can control the Navigation of the application in any way they like.

publicinterfaceIFreshNavigationService{TaskPushPage(Pagepage,FreshBasePageModelmodel,boolmodal=false);TaskPopPage(boolmodal=false);}

Within the PushPage and PopPage you can do any type of navigation that you like, this can be anything from a simple navigation to a advanced nested navigation.

The Framework contains some built in Navigation containers for the different types of Navigation.

Basic Navigation - Built In
varpage=FreshPageModelResolver.ResolvePageModel<MainMenuPageModel>();varbasicNavContainer=newFreshNavigationContainer(page);MainPage=basicNavContainer;
Master Detail - Built In
varmasterDetailNav=newFreshMasterDetailNavigationContainer();masterDetailNav.Init("Menu");masterDetailNav.AddPage<ContactListPageModel>("Contacts",null);masterDetailNav.AddPage<QuoteListPageModel>("Pages",null);MainPage=masterDetailNav;
Tabbed Navigation - Built In
vartabbedNavigation=newFreshTabbedNavigationContainer();tabbedNavigation.AddTab<ContactListPageModel>("Contacts",null);tabbedNavigation.AddTab<QuoteListPageModel>("Pages",null);MainPage=tabbedNavigation;
Implementing Custom Navigation

It's possible to setup any type of Navigation by implementing IFreshNavigationService.There's a sample of this in Sample Application named CustomImplementedNav.cs.

Sample Apps

  • Basic Navigation Sample
  • Tabbed Navigation Sample
  • MasterDetail Navigation Sample
  • Tabbed Navigation with MasterDetail Popover Sample (This is called the CustomImplementedNav in the Sample App)

Inversion of Control (IOC)

So that you don't need to include your own IOC container, FreshMvvm comes with a IOC container built in. It's using TinyIOC underneith, but with different naming to avoid conflicts.

To Register services in the container use Register:

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

To obtain a service use Resolve:

FreshIOC.Container.Resolve<IDatabaseService>();

*This is also what drives constructor injection.

IOC Container Lifetime Registration Options

We now support a fluent API for setting the object lifetime of object inside the IOC Container.

// By default we register concrete types as// multi-instance, and interfaces as singletonsFreshIOC.Container.Register<MyConcreteType>();// Multi-instanceFreshIOC.Container.Register<IMyInterface,MyConcreteType>();// Singleton// Fluent API allows us to change that behaviourFreshIOC.Container.Register<MyConcreteType>().AsSingleton();// SingletonFreshIOC.Container.Register<IMyInterface,MyConcreteType>().AsMultiInstance();// Multi-instance

As you can see below the IFreshIOC interface methods return the IRegisterOptions interface.

publicinterfaceIFreshIOC{objectResolve(TyperesolveType);IRegisterOptionsRegister<RegisterType>(RegisterTypeinstance)whereRegisterType:class;IRegisterOptionsRegister<RegisterType>(RegisterTypeinstance,stringname)whereRegisterType:class;ResolveTypeResolve<ResolveType>()whereResolveType:class;ResolveTypeResolve<ResolveType>(stringname)whereResolveType:class;IRegisterOptionsRegister<RegisterType,RegisterImplementation>()whereRegisterType:classwhereRegisterImplementation:class,RegisterType;}

The interface that's returned from the register methods is IRegisterOptions.

publicinterfaceIRegisterOptions{IRegisterOptionsAsSingleton();IRegisterOptionsAsMultiInstance();IRegisterOptionsWithWeakReference();IRegisterOptionsWithStrongReference();IRegisterOptionsUsingConstructor<RegisterType>(Expression<Func<RegisterType>>constructor);}

PageModel - Constructor Injection

When PageModels are pushed services that are in the IOC container can be pushed into the Constructor.

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

PageModel Important Methods

/// <summary>/// The previous page model, that's automatically filled, on push/// </summary>publicFreshBasePageModelPreviousPageModel{get;set;}/// <summary>/// A reference to the current page, that's automatically filled, on push/// </summary>publicPageCurrentPage{get;set;}/// <summary>/// Core methods are basic built in methods for the App including Pushing, Pop and Alert/// </summary>publicIPageModelCoreMethodsCoreMethods{get;set;}/// <summary>/// This method is called when a page is Pop'd, it also allows for data to be returned./// </summary>/// <param name="returndData">This data that's returned from </param>publicvirtualvoidReverseInit(objectreturndData){}/// <summary>/// This method is called when the PageModel is loaded, the initData is the data that's sent from pagemodel before/// </summary>/// <param name="initData">Data that's sent to this PageModel from the pusher</param>publicvirtualvoidInit(objectinitData){}/// <summary>/// This method is called when the view is disappearing./// </summary>protectedvirtualvoidViewIsDisappearing(objectsender,EventArgse){}/// <summary>/// This methods is called when the View is appearing/// </summary>protectedvirtualvoidViewIsAppearing(objectsender,EventArgse){}

The CoreMethods

Each PageModel has a property called 'CoreMethods' which is automatically filled when a PageModel is pushed, it's the basic functions that most apps need like Alerts, Pushing, Poping etc.

publicinterfaceIPageModelCoreMethods{TaskDisplayAlert(stringtitle,stringmessage,stringcancel);Task<string>DisplayActionSheet(stringtitle,stringcancel,stringdestruction,paramsstring[]buttons);Task<bool>DisplayAlert(stringtitle,stringmessage,stringaccept,stringcancel);TaskPushPageModel<T>(objectdata,boolmodal=false)whereT:FreshBasePageModel;TaskPopPageModel(boolmodal=false);TaskPopPageModel(objectdata,boolmodal=false);TaskPushPageModel<T>()whereT:FreshBasePageModel;}

Page important methods

PageModelInitPropertyChanged

Sample PageModel

[ImplementPropertyChanged]// Use Fody for Property Changed NotificationspublicclassQuoteListPageModel:FreshBasePageModel{IDatabaseService_databaseService;//These are automatically filled via Constructor Injection IOCpublicQuoteListPageModel(IDatabaseServicedatabaseService){_databaseService=databaseService;}publicObservableCollection<Quote>Quotes{get;set;}publicoverridevoidInit(objectinitData){Quotes=newObservableCollection<Quote>(_databaseService.GetQuotes());}//The Framework support standard functions list appeaing and disappearingprotectedoverridevoidViewIsAppearing(objectsender,System.EventArgse){CoreMethods.DisplayAlert("Page is appearing","","Ok");base.ViewIsAppearing(sender,e);}protectedoverridevoidViewIsDisappearing(objectsender,System.EventArgse){base.ViewIsDisappearing(sender,e);}//This is called when a pushed Page returns to this PagepublicoverridevoidReverseInit(objectvalue){varnewContact=valueasQuote;if(!Quotes.Contains(newContact)){Quotes.Add(newContact);}}publicCommandAddQuote{get{returnnewCommand(async()=>{//Push A Page ModelawaitCoreMethods.PushPageModel<QuotePageModel>();});}}Quote_selectedQuote;publicQuoteSelectedQuote{get{return_selectedQuote;}set{_selectedQuote=value;if(value!=null)QuoteSelected.Execute(value);}}publicCommand<Quote>QuoteSelected{get{returnnewCommand<Quote>(async(quote)=>{awaitCoreMethods.PushPageModel<QuotePageModel>(quote);});}}}

Multiple Navigation Services

It’s always been possible to do any type of navigation in FreshMvvm, with custom or advanced scenarios were done by implementing a custom navigation service. Even with this ability people found it a little hard to do advanced navigation scenarios in FreshMvvm. After I reviewed all the support questions that came in for FreshMvvm I found that the basic issue people had was they wanted to be able to use our built in navigation containers multiple times, two primary examples are 1) within a master detail having a navigation stack in a master and another in the detail 2) The ability to push modally with a new navigation container. In order to support both these scenarios I concluded that the FreshMvvm required the ability to have named NavigationServices so that we could support multiple NavigationService’s.

Using multiple navigation containers

Below we’re running two navigation stacks, in a single MasterDetail.

varmasterDetailsMultiple=newMasterDetailPage();//generic master detail page//we setup the first navigation container with ContactListvarcontactListPage=FreshPageModelResolver.ResolvePageModel<ContactListPageModel>();contactListPage.Title="Contact List";//we setup the first navigation container with name MasterPageAreavarmasterPageArea=newFreshNavigationContainer(contactListPage,"MasterPageArea");masterPageArea.Title="Menu";masterDetailsMultiple.Master=masterPageArea;//set the first navigation container to the Master//we setup the second navigation container with the QuoteListvarquoteListPage=FreshPageModelResolver.ResolvePageModel<QuoteListPageModel>();quoteListPage.Title="Quote List";//we setup the second navigation container with name DetailPageAreavardetailPageArea=newFreshNavigationContainer(quoteListPage,"DetailPageArea");masterDetailsMultiple.Detail=detailPageArea;//set the second navigation container to the DetailMainPage=masterDetailsMultiple;

PushModally with new navigation stack

//push a basic page Modallyvarpage=FreshPageModelResolver.ResolvePageModel<MainMenuPageModel>();varbasicNavContainer=newFreshNavigationContainer(page,"secondNavPage");awaitCoreMethods.PushNewNavigationServiceModal(basicNavContainer,newFreshBasePageModel[]{page.GetModel()});//push a tabbed page ModallyvartabbedNavigation=newFreshTabbedNavigationContainer("secondNavPage");tabbedNavigation.AddTab<ContactListPageModel>("Contacts","contacts.png",null);tabbedNavigation.AddTab<QuoteListPageModel>("Quotes","document.png",null);awaitCoreMethods.PushNewNavigationServiceModal(tabbedNavigation);//push a master detail page ModallyvarmasterDetailNav=newFreshMasterDetailNavigationContainer("secondNavPage");masterDetailNav.Init("Menu","Menu.png");masterDetailNav.AddPage<ContactListPageModel>("Contacts",null);masterDetailNav.AddPage<QuoteListPageModel>("Quotes",null);awaitCoreMethods.PushNewNavigationServiceModal(masterDetailNav);

Switching out NavigationStacks on the Xamarin.Forms MainPage

There's some cases in Xamarin.Forms you might want to run multiple navigation stacks. A good example of this is when you have a navigation stack for the authentication and a stack for the primary area of your application.

To begin with we can setup some names for our navigation containers.

publicclassNavigationContainerNames{publicconststringAuthenticationContainer="AuthenticationContainer";publicconststringMainContainer="MainContainer";}

Then we can create our two navigation containers and assign to the MainPage.

varloginPage=FreshMvvm.FreshPageModelResolver.ResolvePageModel<LoginViewModel>();varloginContainer=newFreshNavigationContainer(loginPage,NavigationContainerNames.AuthenticationContainer);varmyPitchListViewContainer=newFreshTabbedNavigationContainer(NavigationContainerNames.MainContainer);MainPage=loginContainer;

The Navigation Container will use the name passed as argument to register in this method

publicFreshTabbedNavigationContainer(string navigationServiceName){NavigationServiceName=navigationServiceName;RegisterNavigation();}protectedvoidRegisterNavigation(){FreshIOC.Container.Register<IFreshNavigationService>(this,NavigationServiceName);}

Once we've set this up we can now switch out our navigation containers.

CoreMethods.SwitchOutRootNavigation(NavigationContainerNames.MainContainer);

That name will be resolved in this method to find the correct Navigation Container

publicvoidSwitchOutRootNavigation(stringnavigationServiceName){IFreshNavigationServicerootNavigation=FreshIOC.Container.Resolve<IFreshNavigationService>(navigationServiceName);}

Custom IOC Containers

The second major request for FreshMvvm 1.0 was to allow custom IOC containers. In the case that your application already has a container that you want to leverage.

Using a custom IOC container is very simple in that you only need to implement a single interface.

publicinterfaceIFreshIOC{objectResolve(TyperesolveType);voidRegister<RegisterType>(RegisterTypeinstance)whereRegisterType:class;voidRegister<RegisterType>(RegisterTypeinstance,stringname)whereRegisterType:class;ResolveTypeResolve<ResolveType>()whereResolveType:class;ResolveTypeResolve<ResolveType>(stringname)whereResolveType:class;voidRegister<RegisterType,RegisterImplementation>()whereRegisterType:classwhereRegisterImplementation:class,RegisterType;

And then set the IOC container in the System.

FreshIOC.OverrideContainer(myContainer);

Other Features/Tips

Customise Navigation Pages

Wondering how to customize the navigation bar in pages, eg control the NavigationPage that's created.

In some instances FreshMvvm creates container NavigationPage's for your sub pages. The NavigationContainer's have an override that allows you to control the creation of this NavigationPage. In the sample below we inherit from FreshTabbedNavigationContainer and override the CreateContainerPage and set the NavigationPage BarBackgroundColor to Blue.

usingSystem;usingXamarin.Forms;namespaceFreshMvvmApp{publicclassNavigationBarCustom:FreshMvvm.FreshTabbedNavigationContainer{publicNavigationBarCustom(){}protectedoverridePageCreateContainerPage(Pagepage){varcontainer=newNavigationPage(page);container.BarBackgroundColor=Color.Blue;returncontainer;}}}

WhenAny

WhenAny is an extension method on INotifyPropertyChanged, it's a shorthand way to subscribe to a property changed event.

In the example below, we use any to link up

[PropertyChanged.AddINotifyPropertyChangedInterface]publicclassContactPageModel:FreshBasePageModel{publicContactPageModel(){this.WhenAny(HandleContactChanged, o=>o.Contact);}voidHandleContactChanged(stringpropertyName){//handle the property changed, nice}publicContactContact{get;set;}}

Related Videos/Quick Start Guides

FreshMvvm n=0 – Mvvm in Xamarin.Forms and Why FreshMvvm

FreshMvvm n=1 : Your first FreshMvvm Application

FreshMvvm n=2 – IOC and Constructor Injection

FreshMvvm n=3: Navigation in FreshMvvm

Implementing custom navigation in FreshMvvm for Xamarin.Forms

TDD in Xamarin Studio – Live Coding FreshMvvm

About

FreshMvvm is a super light Mvvm Framework designed specifically for Xamarin.Forms. It's designed to be Easy, Simple and Flexible.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages


[8]ページ先頭

©2009-2025 Movatter.jp