Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/dotnet-ad/mvvmicro
Minimalist MVVM framework for .NET.
https://github.com/dotnet-ad/mvvmicro
commands lightweight micro mvvm navigation xamarin
Last synced: 3 months ago
JSON representation
Minimalist MVVM framework for .NET.
- Host: GitHub
- URL: https://github.com/dotnet-ad/mvvmicro
- Owner: dotnet-ad
- License: mit
- Created: 2017-04-19T07:57:50.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2019-07-17T15:07:18.000Z (over 5 years ago)
- Last Synced: 2024-11-11T06:29:27.465Z (3 months ago)
- Topics: commands, lightweight, micro, mvvm, navigation, xamarin
- Language: C#
- Size: 93.8 KB
- Stars: 22
- Watchers: 4
- Forks: 5
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
![Schema](./Documentation/Logo.png)
[![NuGet](https://img.shields.io/nuget/v/Mvvmicro.svg?label=NuGet)](https://www.nuget.org/packages/Mvvmicro/) [![Donate](https://img.shields.io/badge/donate-paypal-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=ZJZKXPPGBKKAY&lc=US&item_name=GitHub&item_number=0000001¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted)
Minimalist MVVM framework for .NET.
## Install
Available on [NuGet](https://www.nuget.org/packages/Mvvmicro/).
## Usage
### Observable
A base implementation of `INotifyPropertyChanged` with helper method for raising property changes.
* `Set(ref T field, T newValue, [auto] string propertyName)` : sets the value of the referenced field with the given new value and raises `PropertyChanged` even if its different value that the current one. An `Assignment` will be returned to indicate the change status with `HasChanged`. If the value changed, this object also allows you in to raise other linked properties or commands that depends on the current one with `ThenRaise`.
```csharp
public class HomeViewModel : Observable
{
private string firstname, lastname;
public string Firstname
{
get => this.firstname;
set => this.Set(ref this.firstname, value).ThenRaise(() => this.Fullname);
}
public string Lastname
{
get => this.lastname;
set => this.Set(ref this.lastname, value).ThenRaise(() => this.Fullname);
}
public string Fullname => $"{Firstname} {Lastname}";
}
```### ViewModelBase
An `Observable` object that adds navigation elements. This should be the base class for the view models associated to your application screens. A `NavigationRequested` event is available for your view to subscribe and react to.
```csharp
public class HomeViewModel : ViewModelBase
{
//...
private void NavigateDetail(int id)
{
// "/DayViewModel?id=467674"
this.Navigate((s) =>
{
s.Query.Set(day.Identifier, "id");
});
}
}
``````csharp
public class HomeViewController : UIViewController
{
// ...public HomeViewModel ViewModel { get; } = new HomeViewModel();
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
this.ViewModel.NavigationRequested += OnNavigation;
}
public override void ViewWillDisappear(bool animated)
{
base.ViewDidAppear(animated);
this.ViewModel.NavigationRequested -= OnNavigation;
}
private void OnNavigation(object sender, NavigationArgs nav)
{
this.PerformSegue(nav.Segment.Value, this);
}
}
```### Commands
The `(Async)RelayCommand` classes are helpers for creating `ICommand` synchronous and asynchronous implementations on the fly from methods. An alternate version `(Async)RelayCommand` with a typed parameterer is also provided.
The advantages of using `IAsyncRelayCommand` is :
* **Executing state** : `IsExecuting` property, that can be bound for updating your UI (activity indicators and so on).
* **Managing lifecycle** : `LastSuccededExecution` property, for managing lifecycle of display last successful execution time.
* **Failure management** : `ExecutionFailed` event, thrown whenever a
* **Cancellation** : `Cancel()` call will cancel the tokens given as a parameter of the execution method.
* **Single execution** : when already running, a new execution can't be triggered.**Example:**
```csharp
public class HomeViewModel : ViewModelBase
{
public HomeViewModel()
{
this.UpdateCommand = new AsyncRelayCommand(ExecuteUpdateCommandAsync);
}
public AsyncRelayCommand UpdateCommand { get; }
private Task ExecuteUpdateCommandAsync(CancellationToken token)
{
// ...
}
}
```### Dependency container
A deliberately basic container is provided for managing your dependencies. Declarations may seem too verbose compared to other popular IoC frameworks (*Autofac, Ninject, ...*), but **it doesn't rely on any reflection (which can has a cost in a mobile environment)** for injecting instances into newly created instances.
```csharp
Container.Default.Register((c) => new WebApi(), isInstance: true); // A unique instance for entire lifecycle
Container.Default.Register((c) => new HomeViewModel(c.Get())); // a new instance is created each time the type is requested// ...
var homeViewModel = Container.Default.Get();
```### Observers
Sometimes you wish to listen to observable property changes : if you subscribe to `PropertyChanged` event, memory leaks could append since your observable will keep a reference to your observer in order to notify it.
This is often solved by subscribing to this event when your observer becomes active (*i.e. when your page become visible, like `OnResume` in an Android activity*) and unsubcribing to it when the observable becomes inactive (*i.e. when your page disappears, like `OnPause` in an Android activity*). But what happens if your observable triggers property changes while your observer is inactive : **the pending modifications are never applied to it**! This can be deactivated through `ShouldTriggerPendingChanges` property.
The observer also manages initial values by triggering a change on all registered properties the first time. This can be deactivated through `ShouldTriggerInitialValues` property.
The `NotifyPropertyObserver` solves those requirements :
```csharp
public partial class HomeViewController : UIViewController
{
public HomeViewController(IntPtr ptr) : base(ptr)
{
this.ViewModel = new HomeViewModel();
this.observer = this.ViewModel.CreateObserver(this);
}public HomeViewModel ViewModel { get; }
private NotifyPropertyObserver observer;
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);this.observer
.Observe(vm => vm.Fullname, (vm, value) => this.Title = value)
.Start();
}public override void ViewDidDisappear(bool animated)
{
base.ViewDidDisappear(animated);
this.observer.Stop();
}
}
```## Complementary tools
Bellow, you will find a list of tools that can be used in combination with **Mvvmicro** to build great mobile or desktop application projects.
* [AutoFindViews](https://github.com/aloisdeniel/AutoFindViews) : Auto extract Xamarin.Android layout elements from declared identifiers.
* [StaticBind](https://github.com/aloisdeniel/StaticBind) : View data bindings for Xamarin.
* [Refit](https://github.com/paulcbetts/refit) : Rest client implementation generator.
* [LiteDB](http://www.litedb.org/) : Small embedded NoSQL database.
* [Xamarin Plugins](https://github.com/xamarin/XamarinComponents) : Various abstractions for platform specific behaviours## Roadmap / Ideas
* Create a Fody task for generating properties.
## Why ?
I decided to create this small framework because other alternatives offer often too much stuff for me and include unused or duplicated parts. I also often find their navigation model to be not enough flexible. Finally, it's also a good starting point to learn MVVM to students. That's why this framework includes only the minimal bits I need for the majority of my developments.
## Contributions
Contributions are welcome! If you find a bug please report it and if you want a feature please report it.
If you want to contribute code please file an issue and create a branch off of the current dev branch and file a pull request.
### License
![MIT © Aloïs](https://img.shields.io/badge/licence-MIT-blue.svg)
© [Aloïs Deniel](http://aloisdeniel.github.io)