-
Notifications
You must be signed in to change notification settings - Fork 77
ViewModelBase
- Package: MyToolkit (PCL)
- Platforms: All (PCL)
- Inherits from ObservableObject
Base implementation of a view model.
Properties and methods:
- IsLoading: Boolean property with internal counter. If the property is set to true, a counter gets increased and the return value is only false if the counter is 0. This is useful to have multiple asynchronous running task and the loading state is true until the last task has finished.
- Initialize method which initializes the view model and should be called only once (usually in the view's constructor). The trick is to put most of the initialize logic in this method and not the constructor, because this method is only called when the application is started but not in the Visual Studio designer. This way the view model can be instantiated in the designer and does not throw an exception when using not initialized objects in the view model's constructor (e.g. services resolved by the ServiceLocator).
-
OnLoaded and OnUnloaded: When correctly wired (using the ViewModelHelper
.RegisterViewModel()
method), called when the view has been loaded or unloaded.
The following section shows how to implement a view model for a page and wire the page view with the page view model.
1. Create view model
First create a view model for the view
public class MyPageModel : ViewModelBase
{
private int _myProperty;
public MyPageModel()
{
DoItCommand = new RelayCommand(DoIt);
DoItAsyncCommand = new AsyncRelayCommand(DoItAsync);
}
public ICommand DoItCommand { get; private set; }
public ICommand DoItAsyncCommand { get; private set; }
public int MyProperty
{
get { return _myProperty; }
set { Set(ref _myProperty, value);
}
public override void Initialize()
{
_client = ServiceLocator.Default.Resolve<IMyService>();
}
private void DoIt()
{
// TODO: Add command logic
}
private async Task DoItAsync()
{
// TODO: Add command logic
}
}
As you can see, the service is resolved in the Initialize()
method and not the constructor. This is needed for proper Visual Studio designer support: On design time, there are no services available and accessing them in the constructor would cause an exception. This way the Initialize()
method is only called when the application is really started.
2. Connect the view model to the view
It is recommended to instantiate the view model as resource because this adds code completion/IntelliSense to the XAML editor:
<Paging:MtPage ...>
<Paging:MtPage.Resources>
<ViewModels:MyViewModel x:Key="ViewModel" />
</Paging:MtPage.Resources>
<Grid DataContext="{StaticResource ViewModel}">
...
</Grid>
</Paging:MtPage>
To access the view model in the view's code-behind add a Model property:
public sealed partial class MyPage
{
public MyPageModel Model
{
get { return (MyPageModel)Resources["ViewModel"]; }
}
public MainPage()
{
InitializeComponent();
RegisterViewModel(Model);
// or ViewModelHelper.RegisterViewModel(Model, this);
}
}
The RegisterViewModel()
method of the MtPage class (calls the corresponding ViewModelHelper method) can also be replaced (beware: page state life cycle methods, e.g. LoadState()
, are not triggered this way):
public MainPage()
{
InitializeComponent();
Model.Initialize();
Loaded += (sender, args) => Model.CallOnLoaded();
Unloaded += (sender, args) => Model.CallOnUnloaded();
See ObservableObject for more information on how to implement property change tracking.
A long running asynchronous task should be implemented this way:
public class MyPageModel : ViewModelBase
{
public MyPageModel()
{
DoItAsyncCommand = new AsyncRelayCommand(DoItAsync);
}
public ICommand DoItAsyncCommand { get; private set; }
private async Task DoItAsync()
{
IsLoading = true;
try
{
// TODO: Add your task logic
IsLoading = false;
}
catch (Exception exception)
{
IsLoading = false;
// TODO: Show exception
}
}
}
The IsLoading
property should be bound to a ProgressIndicator, ProgressRing or the Windows Phone system tray's progress bar (easiest way is by using the ViewModelHelper.BindViewModelToStatusBarProgress method).