📜 ⬆️ ⬇️

MugenMvvmToolkit - cross-platform MVVM framework

MugenMvvmToolkit


Introduction


The MVVM pattern is well known, many articles have been written about it, probably every NET developer has come across or heard about this pattern. The purpose of this article is to tell about the own implementation of this pattern.
MugenMvvmToolkit - is a cross-platform implementation of the MVVM pattern and currently supports the following platforms:


Data binding


I would like to start acquaintance with the project with an element without which MVVM cannot exist - this is Data Binding. It is the data binding mechanism that allows you to clearly separate the abstractions of View and ViewModel between each other.
Application developers for the WPF, Silverlight, Windows Store and Windows Phone platforms are familiar with the standard implementation of the Binding mechanism. It is a powerful system covering all major tasks. However, it has a number of flaws, which pushed to create its own implementation of Binding. Below are the most significant, in my opinion, disadvantages:

If you work only on one platform, you can put up with these shortcomings and apply various “workarounds”. But since the project is designed for many platforms, some of which do not even have standard Binding, it was decided to create their own implementation, which has the same capabilities on all platforms.
The result is a Binding implementation with the following capabilities:


MVVM implementation features


At the moment there are a huge number of different MVVM frameworks, but most of them look about the same:

Probably, such a framework was written by everyone, but such implementations are far from ideal and do not solve the main problems of MVVM, such as:

The main features of MugenMvvmToolkit:



Navigation


Separately, I would like to consider the navigation between the ViewModel . Navigation in MVVM is one of the most difficult topics, including displaying dialog boxes, adding tabs to TabControl , showing pages for mobile applications, etc. This topic is difficult because on different platforms the same ViewModel can be a dialog box, Page (WinRT, WP, WPF, SL), Activity , Fragment (Android), ViewController (iOS), etc. At the same time, the API for working with the ViewModel should look the same regardless of the platform, since for ViewModel no difference how to display yourself.
For a start, let's look at examples of how navigation works on different platforms.

An example of how to display a dialog box on WPF
 //         var mainWindow = new MainWindow(); //         . mainWindow.Init(args); if (!mainWindow.ShowDialog().GetValueOrDefault()) return; //      ,      . 


For WPF, everything is very simple; we ourselves control the creation of the window, its initialization, and we can easily find out when the window was closed.
Example of navigation to a new Activity (Xamarin.Android)
 //     Activity,    ,     . var page2 = new Intent (this, typeof(Page2)); //      page2.PutExtra ("arg1", arg) StartActivity (page2); //  ,  ,    Activity 


Example of navigation to a new Page (WinRT and Windows phone)
 //       Android. NavigationService.Navigate(typeof(Page2), arg); 


Now let's look at how navigation works in existing MVVM frameworks, for example, let's take a fairly well-known project MvvmCross :
MvvmCross navigation example
 ShowViewModel<DetailViewModel>(new DetailParameters() { Index = 2 }); 

DetailViewModel must have an Init method that accepts the DetailParameters class:
 public void Init(DetailParameters parameters) { // use the parameters here } 


At the same time, the DetailParameters object must be serializable, therefore no complex objects can be transferred. With this approach, it is also very difficult to get the result from the DetailViewModel after the navigation is completed. The approach in MvvmCross is very similar to standard navigation for mobile platforms. You specify the type of the ViewModel , the parameter being serializable and the system displays the View and associates it with the ViewModel . At the same time, it is quite difficult to find out from one ViewModel when another ViewModel was closed. All these restrictions are due to the fact that on mobile devices your application can be completely unloaded from memory, and then restored again, and then there is a problem with saving and restoring state. Basically, this problem is solved by saving the navigation path and serializing the navigation parameters so that they can be restored later.
Compared to WPF, this approach is inconvenient, but MugenMvvmToolkit allows you to use navigation similar to WPF for all platforms. The basic idea is the ability to serialize a delegate (the async / await state machine class), which should be executed after the ViewModel closed. Consider an example, you need from Vm1 , show Vm1 and process the result after Vm1 closed, while it does not matter which platform and which display will be on Vm2 :
MugenMvvmToolkit navigation example
 public class Vm2 : ViewModelBase { public void InitFromVm1() { } public object GetResult() { return null; } } public class Vm1 : ViewModelBase { public async void Open() { var vm2 = GetViewModel<Vm2>(); //     ,     . vm2.InitFromVm1(); //   IAsyncOperation, //         Vm2 IAsyncOperation<bool> asyncOperation = vm2.ShowAsync(Vm2CloseCallback); //     asyncOperation.ContinueWith(Vm2CloseCallback); //      await await asyncOperation; //      Vm2 //    var result = vm2.GetResult(); } private void Vm2CloseCallback(IOperationResult<bool> operationResult) { //    var result = ((Vm2)operationResult.Source).GetResult(); } private void Vm2CloseCallback(Vm2 vm2, IOperationResult<bool> operationResult) { //    var result = vm2.GetResult(); } } 


And this code will work regardless of the platform and the way Vm2 displayed, and even if your application is unloaded from memory, all registered delegates and state machines will also be saved and then restored. If you want to use async / await on a WinRT or Windows Phone platform, you will need to install a plugin for Fody , this is due to the limitations of reflection for these platforms.
One of the features of MugenMvvmToolkit is deep integration with each platform, it allows you to use all the advantages of the platform within MVVM.
')

WPF and SL


Features MugenMvvmToolkit for WPF \ SL:

In order to use Binding, you need to install an additional package from nuget , after installation you will have the DataBindingExtension class and the attached property View.Bind .
Binding Usage Examples
 <TextBlock Text="{DataBinding 'Text.ExtensionMethod(Text.Count())'}" /> <TextBlock Text="{DataBinding '$string.IsNullOrEmpty(Text) ? \'String is empty\' : \'String is not empty\''}"/> <TextBlock View.Bind="Text Text.ExtensionMethod(Text.Count())"/> <TextBlock View.Bind="Text $string.IsNullOrEmpty(Text) ? 'String is empty' : 'String is not empty'"/> <Button Click="{DataBinding Path=Command, ToggleEnabledState=False}" /> <Button View.Bind="Click Command, ToggleEnabledState=False" /> <TextBox TextChanged="{DataBinding 'EventMethodMultiParams($self.Text, $args.UndoAction)'}" /> <TextBox View.Bind="TextChanged EventMethodMultiParams($self.Text, $args.UndoAction)" /> 



WinRT and Windows phone


Features MugenMvvmToolkit for WinRT \ WinPhone:

In order to use Binding, you need to install an additional package from nuget , after installation you will View.Bind attached property View.Bind . To use it, you must add a namespace:
 xmlns:markupExtensions="clr-namespace:MugenMvvmToolkit.MarkupExtensions;assembly=MugenMvvmToolkit.WinPhone" xmlns:markupExtensions="using:MugenMvvmToolkit.MarkupExtensions" 

Binding Usage Examples
 <TextBlock markupExtensions:View.Bind="Text Text.ExtensionMethod(Text.Count())"/> <TextBlock markupExtensions:View.Bind="Text $string.IsNullOrEmpty(Text) ? 'String is empty' : 'String is not empty'"/> <Button markupExtensions:View.Bind="Click Command, ToggleEnabledState=False" /> <TextBox markupExtensions:View.Bind="TextChanged EventMethodMultiParams($self.Text, $args.UndoAction)" /> 



Winforms


Features MugenMvvmToolkit for WinForms:

In order to use Binding it is necessary:
  1. Create a class that inherits from the Binder class:
     public class ViewBinder : Binder { public ViewBinder() { } public ViewBinder(IContainer container) : base(container) { } } 

  2. Compile the project, open the designer with the desired form, go to the Toolbox tab, the ViewBinder class should appear ViewBinder
  3. Add it to the form, then you can add Binding using the Bindings property.

Binding Usage Examples
 <Bindings> <addToolStripButton Click="AddNodeCommand" /> <removeToolStripButton Click="RemoveNodeCommand" /> <treeView ItemsSource="Nodes" CollectionViewManager="$treeNodeCollectionViewManager" ItemTemplate="$treeNodeTemplate" SelectedNode.DataContext="SelectedNode, Mode=OneWayToSource" /> <nameTextBox Text="SelectedNode.Name, Mode=TwoWay, Fallback='Nothing selected'" /> <validCheckBox Checked="SelectedNode.IsValid, Mode=TwoWay" /> </Bindings> 



Xamarin.Android


Features MugenMvvmToolkit for Xamarin.Android:

Binding
 <TextView android:layout_width="fill_parent" android:layout_height="fill_parent" pkg:Bind="Text $Format('Name: {0}, Id: {1}', Name, Id)" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" pkg:Bind="Click Command" /> 



Xamarin.iOS


MugenMvvmToolkit Xamarin.iOS:


Xamarin.Forms


MugenMvvmToolkit Xamarin.Forms:

Binding
 <Entry Text="{mugen:DataBinding Name, Mode=TwoWay, Validate=True}" /> <Button Command="{mugen:DataBinding $Relative(ListView).DataContext.ShowCommand}" Text="{mugen:DataBinding Item1}" CommandParameter="{mugen:DataBinding Item2}" /> 



Conclusion


. – , , MVVM , .
.

References:




PS , .

Source: https://habr.com/ru/post/236745/


All Articles