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

Show/Hide Windows the MVVM way

Rate me:
Please Sign up or sign in to vote.
4.82/5 (4 votes)
17 Jan 2015CPOL 14.6K   8  
Solution to the problem on how to databind Windows visibility to ViewModels

Introduction

Some idea to handle Window and Dialog the MVVM way.

Background

Recently. In my take over the world app, I started to write Window and Dialog (aka Modal Window) ViewModel. I wanted to be able to handle the Window through data binding. I came up with this solution.

Using the code

In a MVVM it is customary to handle most, if not all, app state in your view model. Leaving the UserControl to be empty shell for loading XAML UI definition. As I started to add dialog & window to my app I hit a limitation of the MVVM tool I am familiar with.

I was trying to write

C#
myDialogViewModel.Show = true; // must show window, somehow...

I came up with this utility class hosting Window visibility as AttachedProperties

C#
public class Dialog
{
 public static bool GetShowDialog(Window obj) { return (bool)obj.GetValue(ShowDialogProperty); }

 public static void SetShowDialog(Window obj, bool value) { obj.SetValue(ShowDialogProperty, value); }

 public static readonly DependencyProperty ShowDialogProperty = ...;

 public static bool GetShowWindow(Window obj) { return (bool)obj.GetValue(ShowWindowProperty); }

 public static void SetShowWindow(Window obj, bool value) { obj.SetValue(ShowWindowProperty, value); }

 public static readonly DependencyProperty ShowWindowProperty = ...;
}

I can then use it in XAML as follow:

XML
<MyDialog
 xmlns:gx="clr-namespace:MyApp"
 Title="My Dialog"
 gx:Dialog.ShowDialog="{Binding Show}"
 >
....
</MyDialog>

And voila! Full MVVM dialog and Windows.

Full Source Code

Here is the complete implementation of the Dialog class.

C#
public class Dialog
{
 public static bool GetShowDialog(Window obj) { return (bool)obj.GetValue(ShowDialogProperty); }

 public static void SetShowDialog(Window obj, bool value) { obj.SetValue(ShowDialogProperty, value); }

 public static readonly DependencyProperty ShowDialogProperty = DependencyProperty.RegisterAttached("ShowDialog", typeof(bool), typeof(Dialog)
  , new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (o, e) => OnShowDialogChanged(o, (bool)e.NewValue)));

 private static void OnShowDialogChanged(DependencyObject sender, bool state)
 {
  var w = sender as Window;
  if (w != null)
  {
   EventHandler closed = (o, e) => { SetShowDialog(w, false); };
   if (state)
   {
    w.Closed += closed;
    // WARNING: this is blocking => screw 2-way binding
    // => call in a Dispatcher
    w.Dispatcher.BeginInvoke(new Action(delegate { if (GetShowDialog(w)) w.ShowDialog(); }));
   }
   else
   {
    w.Closed -= closed;
    w.Close();
   }
  }
 }

 public static bool GetShowWindow(Window obj) { return (bool)obj.GetValue(ShowWindowProperty); }

 public static void SetShowWindow(Window obj, bool value) { obj.SetValue(ShowWindowProperty, value); }

 public static readonly DependencyProperty ShowWindowProperty = DependencyProperty.RegisterAttached("ShowWindow", typeof(bool), typeof(Dialog)
  , new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (o, e) => OnShowWindowChanged(o, (bool)e.NewValue)));

 private static void OnShowWindowChanged(DependencyObject sender, bool state)
 {
  var w = sender as Window;
  if (w != null)
  {
   EventHandler closed = (o, e) => { SetShowWindow(w, false); };
   if (state)
   {
    w.Closed += closed;
    w.Show();
   }
   else
   {
    w.Closed -= closed;
    w.Close();
   }
  }
 }
}

 

Points of Interest

Ever more MVVM goodness! I didn't see many solution for hiding/showing Windows. I hope this will help!

History

Initial release on 18/01/2015

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) http://www.ansibleww.com.au
Australia Australia
The Australia born French man who went back to Australia later in life...
Finally got over life long (and mostly hopeless usually, yay!) chronic sicknesses.
Worked in Sydney, Brisbane, Darwin, Billinudgel, Darwin and Melbourne.

Comments and Discussions

 
-- There are no messages in this forum --