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
myDialogViewModel.Show = true;
I came up with this utility class hosting Window visibility as AttachedProperties
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:
<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.
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;
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