Click here to Skip to main content
15,891,431 members
Articles / Desktop Programming / WPF
Tip/Trick

MVVM - Invoke call from ViewModel in the View Domain

Rate me:
Please Sign up or sign in to vote.
4.00/5 (2 votes)
9 Oct 2012Apache2 min read 21.9K   4  
Highlights some code from "VERY Easy MVVM "MVVMExtraLite" (MVVMXL) - Free and tiny source code" from XAML guy that I found simple and useful.

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.

C#
// From the Main ViewModel, Standard use of commands in MVVM
// Code for the Relay Command and INotification is additionally needed

bool? invokeCallFlagVm;
public bool? InvokeCallFlagVm
{
    get { return invokeCallFlagVm; }
    set { SetProp(ref invokeCallFlagVm, value); // My function for set value and Inotify }
}

RelayCommand invokeWindowCall;
public ICommand InvokeWindowCall
{
    get { return invokeWindowCall ?? 
          (invokeWindowCall = new RelayCommand(x => OnInvokeWindowCall(x))); }
}

public void OnInvokeWindowCall(object p)
{
    // Note Added: use of Dispatcher v.s. strict separation View-ViewModel
    // Introduced to insure Open New Window before closing current ???
    Application.Current.Dispatcher.BeginInvoke
      (DispatcherPriority.Background, new Action(() =>
      {
        InvokeCallFlagVm = InvokeCallFlagVm == null
            ? true
            : !InvokeCallFlagVm;
      }));
}
XML
// 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>
C#
// The Attached property, considered part of the View

public class AttachedInvokeWindowCall
{
    // from http://gallery.technet.microsoft.com/VERY-Easy-MVVM-MVVMExtraLit-54353183
    // Apache License Version 2.0  http://www.apache.org/licenses/
    // Names are changed, body of InvokeCallFlagChanged minor modification

    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;
        //   var win = new Window2 { DataContext = new ViewModelWindow2() };
        //   win.Show();
        // or
        //   window.Close(); 

        // I defined function InvokedCall in the codebehind in 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.

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0


Written By
Netherlands Netherlands
Retired hobby programmer.

Comments and Discussions

 
-- There are no messages in this forum --