How to Implement Custom ViewMediator
Sometimes there is arises some necessity in using of non standard views. MugenMvvm provided with some abstraction that allows to end-user connect non-standard views and viewmodels. It's abstraction called "ViewMediator".
As we know, "mediator" is a behavioral pattern that encapsulates how a set of objects interact. In our case, a typical "mediator" encapsulates interaction of view and viewmodel.
So, in order to use non standard views in your project you have to follow the next algorithm:
- Create your own view mediator.
- Register it in
ServiceProvider
.
Step One: Creation
In order to create your own view mediator you have to implement IWindowViewMediator
. The members of this interface are quite simple:
IsOpen
- property to check view is opened;View
- reference for the view;ViewModel
- reference for the viewmodel;ShowAsync
- method that allows to show view;CloseAsync
- method that allows to close view;UpdateView
- method that allows to update view;
public interface IWindowViewMediator
{
bool IsOpen { get; }
[CanBeNull]
object View { get; }
[NotNull]
IViewModel ViewModel { get; }
Task ShowAsync([CanBeNull] IOperationCallback callback,
[CanBeNull] IDataContext context);
Task<bool> CloseAsync([CanBeNull] object parameter);
void UpdateView([CanBeNull] object view, bool isOpen,
[CanBeNull] IDataContext context);
}
By the way there is exists base implementation of this interface in MugenMvvm (WindowViewMediatorBase).
This base implementation contains quite many lines of code, but the main abstract methods are:
protected abstract void ShowView([NotNull] TView view, bool isDialog,
IDataContext context);
protected abstract void ActivateView([NotNull] TView view,
IDataContext context);
protected abstract void InitializeView([NotNull] TView view,
IDataContext context);
protected abstract void CleanupView([NotNull] TView view);
protected abstract void CloseView([NotNull] TView view);
Let's take an example. As example we will take an implementation of WindowViewMediatorBase for WPF:
public class WindowViewMediator : WindowViewMediatorBase<IWindowView>
{
private readonly NavigationWindow _window;
public WindowViewMediator([NotNull] IViewModel viewModel, [NotNull] IThreadManager threadManager,
[NotNull] IViewManager viewManager, [NotNull] IWrapperManager wrapperManager, [NotNull] IOperationCallbackManager callbackManager)
: base(viewModel, threadManager, viewManager, wrapperManager, callbackManager)
{
}
internal WindowViewMediator([NotNull] NavigationWindow window, [NotNull] IViewModel viewModel, [NotNull] IThreadManager threadManager,
[NotNull] IViewManager viewManager, [NotNull] IWrapperManager wrapperManager, [NotNull] IOperationCallbackManager callbackManager)
: base(viewModel, threadManager, viewManager, wrapperManager, callbackManager)
{
Should.NotBeNull(window, nameof(window));
_window = window;
}
protected override void ShowView(IWindowView view, bool isDialog, IDataContext context)
{
if (isDialog)
view.ShowDialog();
else
view.Show();
}
protected override void ActivateView(IWindowView view, IDataContext context)
{
view.Activate();
}
protected override void CloseView(IWindowView view)
{
view.Close();
}
protected override void InitializeView(IWindowView windowView, IDataContext context)
{
windowView.Closing += OnClosing;
}
protected override void CleanupView(IWindowView windowView)
{
windowView.Closing -= OnClosing;
}
public override IViewModel ViewModel
{
get
{
if (_window == null)
return base.ViewModel;
if (ThreadManager.IsUiThread)
return ToolkitExtensions.GetDataContext(_window.Content) as IViewModel ?? base.ViewModel;
return base.ViewModel;
}
}
private void OnClosing(object sender, CancelEventArgs cancelEventArgs)
{
OnViewClosing(sender, cancelEventArgs);
}
}
As you can see, WindowViewMediator
is quite straightforward.
Step Two: Registration
To register your mediator you can choose one of the next approaches:
- Register through
ServiceProvider.WindowViewMediatorFactory
; - Override
CreateWindowViewMediator
method inDynamicViewModelWindowPresenter
.
Let's see how first approach works. First of all, let's create a module in your project:
public class MyModule : IModule
{
public int Priority { get; } = 0;
public bool Load(IModuleContext context)
{
return true;
}
public void Unload(IModuleContext context)
{
}
}
And now just assign ServiceProvider.WindowViewMediatorFactory
to our delegate:
public class MyModule : IModule
{
public int Priority { get; } = 0;
public bool Load(IModuleContext context)
{
ServiceProvider.WindowViewMediatorFactory = (model, type, arg3) =>
{
if (type.IsAssignableFrom(typeof(NonStandardView)))
{
return new WindowViewMediator(model, /* and other parameters */);
}
return null;
};
return true;
}
public void Unload(IModuleContext context)
{
}
}
In our delegate we check that passed type is the type assignable from non standard view type and return appropriate type of mediator. Else return null.
Updated almost 8 years ago