-
Notifications
You must be signed in to change notification settings - Fork 0
MVVM
In this package you will find the default MVVM implementations like PropertyChanged and some "convenience implementations" to make your life a little easier.
The BindingBase is our default INotifyPropertyChanged implementation.
- implementation of
INofityPropertyChanged - convenient methods
GetValueandSetValueto easily declare a property and useINotifyPropertyChanged -
INotifyPropertyChangedfor nested classes -
INotifyPropertyChangedfor dependent properties (e.g. update message forAgeproperty whenDateOfBirthhas changed) - controlling the
INotifyPropertyChangedevents via attributes - automatically updating
ICommand.CanExecuteif there is anyICommandin the class
public class Model :
BindingBase
{
// simple property with PropertyChanged support
public string Name
{
get => GetValue<string>();
set => SetValue(value);
}
// add custom PropertyChanged handler
public DateTime DateOfBirth
{
get => GetValue<DateTime>();
set => SetValue(value, OnDateOfBirthChanged);
}
private void OnDateOfBirthChanged (object sender, PropertyChangedEventArgs eventArgs) { ... }
// add custom PropertyChanged handler
// and custom PropertyChanging handler
public Guid Id
{
get => GetValue<Guid>();
set => SetValue(value, OnIdChanged, OnIdChanging);
}
private void OnIdChanged (object sender, PropertyChangedEventArgs eventArgs) { ... }
private void OnIdChanging (object sender, PropertyChangingEventArgs eventArgs) { ... }
// add custom PropertyChanged action
public string Url
{
get => GetValue<string>();
set => SetValue(value, (url) =>
{
if (!url.EndsWith('/'))
url += "/";
});
}
}1. The basic one: ViewModelBase
This is a very basic implementation and just provides a property public bool IsInitialized to state wether this instance has been set up using the InitializeAsync method.
This method is automatically invoked when creating instances using the ViewModelFactory.
Example usage:
public class CalendarViewModel :
ViewModelBase
{
public override async Task InitializeAsync()
{
// some async logic like database access here...
}
}2. The model-dependent one: ViewModelBase<TModel>
The generic implementation extends the ViewModelBase by providing the InitializeAsync<TModel>(TModel model) method. This way it is possible to initialise your ViewModel instance directly with a model that is necessary for the instance anyways.
Example usage:
public class DetailsViewModel :
ViewModelBase<Item>,
IDetailsViewModel
{
public Item Item
{
get => GetValue<Item>();
private set => SetValue(value);
}
public override async Task InitializeAsync(Item model)
{
Item = model;
}
}
// Navigation example:
navigationService.ShowAsync<IDetailsViewModel, Item>(selectedItem);3. Simplified navigation: Navigation.ViewModelBase
The implementations in the namespace CodeMonkeys.MVVM.ViewModels.Navigation are making navigating between ViewModels much easier since there is no need to store and call the IViewModelNavigationService instance every time.
Instead, these ViewModel implementations are resolving an instance of the service itself and encapsulating the most common methods:
public async Task ShowAsync<TDestinationViewModel>public async Task CloseAsync()public async Task CloseAsync<TListenerViewModel>()public async Task CloseAsync<TListenerViewModel, TResult>(TResult result)In addition, these ViewModels are called when the page is closed (e.g. because the user is navigating back or forward).
Please note that the CloseAsync method only works when registering specific ViewModel type to specific View type at navigation service bootstrap (e.g. NavigationService.Register<MainViewModel, MainView>();).
If you want to use interfaces for registration, you have to use the Navigation.ViewModelBase<TInterface>.
// CodeMonkeys.MVVM.ViewModels.ViewModelBase:
public class ItemListViewModel :
CodeMonkeys.MVVM.ViewModels.ViewModelBase
{
private readonly IViewModelNavigationService _navigationService;
public ICommand ItemSelected => new AsyncCommand<Item>(HandleItemSelected);
public ItemListViewModel(IViewModelNavigationService navigationService)
{
_navigationService = navigationService;
}
private async Task HandleItemSelected (Item selectedItem)
{
_navigationService.ShowAsync<IItemDetailsViewModel, Item>(selectedItem);
}
}
// CodeMonkeys.MVVM.ViewModels.Navigation.ViewModelBase:
public class ItemListViewModel :
CodeMonkeys.MVVM.ViewModels.Navigation.ViewModelBase
{
public ICommand ItemSelected => new AsyncCommand<Item>(HandleItemSelected);
private async Task HandleItemSelected (Item selectedItem)
{
ShowAsync<IItemDetailsViewModel, Item>(selectedItem);
}
}Note that there is also a "navigation implementation" of the ViewModelBase<TModel>.
It is also located in the CodeMonkeys.MVVM.ViewModels.Navigation namespace and called ViewModelBase<TInterface, TModel>
The ViewModelFactory
You can find the ViewModelFactory in the namespace CodeMonkeys.MVVM.Factories.
In order to use the factory, you need to configure it calling the ViewModelFactory.Configure method and passing an IDependencyResolver instance and optionally an ILogService instance, too.
After setting up the factory, you are able to create ViewModel instances with it, using one of the following methods:
public static TViewModelInterface Resolve<TViewModelInterface>(bool initialize = true)public static async Task<TViewModelInterface> ResolveAsync<TViewModelInterface>(bool initialize = true)public static async Task<TViewModelInterface> ResolveAsync<TViewModelInterface, TModel>(TModel model)The bool initialize = true parameter indicates wether the Initialize method of your IViewModel should be called.
The namespace of our Commands is CodeMonkeys.MVVM.Commands, so your using directive would look like this:
using CodeMonkeys.MVVM.Commands;1. Keeping it simple: Command
public class LoginViewModel
{
public string UserName
{
get => return GetValue<string>();
set => SetValue(value);
}
public string Password
{
get => return GetValue<string>();
set => SetValue(value);
}
public ICommand ClearUserNameCommand => new Command(() => UserName = string.Empty);
public ICommand ClearPasswordCommand { get; private set; }
public LoginViewModel()
{
ClearPasswordCommand = new Command(ClearPasswordField);
}
private void ClearPasswordField() { ... }
}2. Defining the parameter type: Command<TParameter>
public class ItemsListViewModel
{
public IList<Item> Items
{
get => return GetValue<IList<Item>>();
set => SetValue(value);
}
public ICommand SelectItemCommand => new Command<Item>((item) => SelectItem(item));
private void SelectItem (Item selectedItem) { ... }
}3. Want to do some asynchronous stuff? AsyncCommand
public class LoginViewModel
{
public ICommand LoginCommand => new AsyncCommand(Login);
private async Task Login () { ... }
}4. Async and defined: AsyncCommand<TParameter>
public class ItemsListViewModel
{
public IList<Item> Items
{
get => return GetValue<IList<Item>>();
set => SetValue(value);
}
public ICommand ShowItemDetailsCommand => new AsyncCommand<Item>((item) => ShowItemDetails(item));
private async Task ShowItemDetails (Item selectedItem) { ... }
}- track changes and commit/undo
- overview and examples