Introduction
In the Online Samples in Visual Studio 2012 Express I found a project
"VERY Easy MVVM "MVVMExtraLite" (MVVMXL) - Free and tiny source code" from
XAML Guy. It covers code
for RelayCommand, Mediator, EventToCommand, and an example
of an AttachedProperty (CloseWindow from ViewModel).
My tip/trick for the MVVM beginner is to look at the code presented in that project. We will highlight here the code of the Attached Property to invoke from the ViewModel
a call in the View domain (Open Window, Close Window, function call in Window).
There are now many variants of this, see for example "Close window from ViewModel"
from Shimmy, "Handling a Window's Closed
and Closing events in the View-Model" by Nish Sivakumar, and "How to close a View from a ViewModel ?"
by Jeremy Alles. The solution presented here is just a stripped down version of Nish Siakumar's solution. A topic is not to break the separation between
the View and the ViewModel.
Basic Idea
- The
ViewModel
contains a bool?
property InvokeCallFlagVm
.
- The
ViewModel
contains an ICommand
InvokeWindowCall
that toggles InvokeCallFlagVm
.
The command can be bound to in the View (MainWindow
or UserControl
). This is just standard MVVM technique.
- In the
MainWindow.XAML
an attached property AttachedInvokeWindowCall.InvokeCallFlag
is attached to the MainWindow
and
bound to the InvokeCallFlagVm
from the ViewModel.
- If the attached property is changed a Call in the View domain is invoked.
Code Snippets
This is basically just a copy from "VERY Easy MVVM "MVVMExtraLite" (MVVMXL) - Free and tiny
source code". However following the license of the original code I clearly point out that the original code has been changed: different names used, we use the code
in the ViewModel class itself, the datacontext is specified in XAML and the invoked call is slightly different.
bool? invokeCallFlagVm;
public bool? InvokeCallFlagVm
{
get { return invokeCallFlagVm; }
set { SetProp(ref invokeCallFlagVm, value); }
RelayCommand invokeWindowCall;
public ICommand InvokeWindowCall
{
get { return invokeWindowCall ??
(invokeWindowCall = new RelayCommand(x => OnInvokeWindowCall(x))); }
}
public void OnInvokeWindowCall(object p)
{
Application.Current.Dispatcher.BeginInvoke
(DispatcherPriority.Background, new Action(() =>
{
InvokeCallFlagVm = InvokeCallFlagVm == null
? true
: !InvokeCallFlagVm;
}));
}
// From the MainView.XAML, binding with given datacontext works..
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
.....
xmlns:vw="clr-namespace:View"
vw:AttachedInvokeWindowCall.InvokeCallFlag="{Binding InvokeCallFlagVm}"
>
<Window.DataContext>
<vm:MainVm x:Name="MyMainVm"/>
</Window.DataContext>
public class AttachedInvokeWindowCall
{
public static readonly DependencyProperty InvokeCallFlagProperty =
DependencyProperty.RegisterAttached("InvokeCallFlag", typeof(bool?),
typeof(AttachedInvokeWindowCall),
new UIPropertyMetadata(null, InvokeCallFlagChanged));
public static void SetInvokeCallFlag(DependencyObject obj, bool? value)
{
obj.SetValue(InvokeCallFlagProperty, value);
}
public static void InvokeCallFlagChanged
(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var window = sender as WpfApplication1.MainWindow;
if (window != null && e.NewValue != null) window.InvokedCall();
}
}
Points of interest
The MVVMXL project presents compact basic code. It does not resolve all my MVVM topics, such as injecting notifications in
an existing given class or how to communicate in a simple way if the ViewModel is split in several classes
(for very complex scenario's look at the philosophy behind PRISM).
For Dialogue Windows I often use pop-ups (made draggable).
I used InvokedCall
in an application with a zoomable image. I handled the zoom entirely in the View and had in code-behind a reset of the transformation matrix.
When I refactored a button to a UserControl that button had no acces to the reset function. Alternative solution: bind to a transformation matrix in the viewmodel.
I assume that the Mediator could also be used for an alternative solution but that feels for me a little counter intuitive.
It feels a little weird, just copying some code and add minor comment to that, but I found the code simple and useful and I hope this little Tip/Trick is
useful for you too.