Interactivity - Open Views from ViewModel
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interactivity;
namespace MyApp.View
{
public class OpenCloseWindowBehavior : Behavior<Window>
{
private Window _windowInstance;
/// <summary>
/// Gets or sets the type of the window.
/// </summary>
/// <value>
/// The type of the window.
/// </value>
public Type WindowType
{
get { return (Type)GetValue(WindowTypeProperty); }
set { SetValue(WindowTypeProperty, value); }
}
/// <summary>
/// Gets or sets a value indicating whether this <see cref="OpenCloseWindowBehavior"/> is open.
/// </summary>
/// <value>
/// <c>true</c> if open; otherwise, <c>false</c>.
/// </value>
public bool Open
{
get { return (bool)GetValue(OpenProperty); }
set { SetValue(OpenProperty, value); }
}
/// <summary>
/// Gets or sets the command parameter.
/// </summary>
/// <value>
/// The command parameter.
/// </value>
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
/// <summary>
/// The window type property
/// </summary>
public static readonly DependencyProperty WindowTypeProperty =
DependencyProperty.Register("WindowType", typeof(Type), typeof(OpenCloseWindowBehavior), new PropertyMetadata(null));
/// <summary>
/// The open property
/// </summary>
public static readonly DependencyProperty OpenProperty =
DependencyProperty.Register("Open", typeof(bool), typeof(OpenCloseWindowBehavior), new PropertyMetadata(false, OnOpenChanged));
/// <summary>
/// The command parameter property
/// </summary>
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object), typeof(OpenCloseWindowBehavior), new PropertyMetadata(null));
/// <summary>
/// Called when [open changed].
/// </summary>
/// <param name="d">The d.</param>
/// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
/// <exception cref="System.ArgumentException"></exception>
private static void OnOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var me = (OpenCloseWindowBehavior)d;
if ((bool)e.NewValue)
{
object instance;
if (me.CommandParameter != null)
{
instance = Activator.CreateInstance(me.WindowType, me.CommandParameter);
}
else
{
instance = Activator.CreateInstance(me.WindowType);
}
if (instance is Window)
{
Window window = (Window)instance;
window.Closing += (s, ev) =>
{
if (me.Open) // window closed directly by user
{
me._windowInstance = null; // prevents repeated Close call
me.Open = false; // set to false, so next time Open is set to true, OnOpenChanged is triggered again
}
};
window.ShowDialog();
me._windowInstance = window;
}
else
{
// could check this already in PropertyChangedCallback of WindowType - but doesn't matter until someone actually tries to open it.
throw new ArgumentException(string.Format("Type '{0}' does not derive from System.Windows.Window.", me.WindowType));
}
}
else
{
if (me._windowInstance != null)
me._windowInstance.Close(); // closed by viewmodel
}
}
}
}
<Window x:Class="MyApp.View.MyWindow2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="My Window" Height="300" Width="300">
<TextBlock Text="Window 2"/>
</Window>
<Window x:Class="MyApp.View.MyWindow1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="My Window" Height="300" Width="300">
<TextBlock Text="Window 1"/>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interactivity;
namespace MyApp.ViewModel
{
public class MyViewModel
{
#region Fields
private bool myWindow1Open;
private bool myWindow2Open;
#endregion
#region Properties
public bool MyWindow1Open
{
get
{
return myWindow1Open;
}
set
{
myWindow1Open = value;
OnPropertyChanged();
}
}
public bool MyWindow2Open
{
get
{
return myWindow2Open;
}
set
{
myWindow2Open = value;
OnPropertyChanged();
}
}
#endregion
public ICommand OpenWindow1Command
{
get { return new DelegateCommand<bool>(OpenWindow1); }
}
private void OpenWindow1()
{
MyWindow1Open = true;
}
public ICommand OpenWindow2Command
{
get { return new DelegateCommand<bool>(OpenWindow2); }
}
private void OpenWindow2(bool open)
{
MyWindow2Open = true;
}
}
}
<Window x:Class="MyApp.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:vm="clr-namespace:MyApp.ViewModel;assembly=MyApp.ViewModel"
xmlns:local="clr-namespace:MyApp.View"
mc:Ignorable="d"
Title="My Window" Height="300" Width="300">
<i:Interaction.Behaviors>
<local:OpenCloseWindowBehavior WindowType="local:MyWindow1" Open="{Binding vm:MyWindow1Open, Mode=TwoWay}"/>
<local:OpenCloseWindowBehavior WindowType="local:MyWindow2" Open="{Binding vm:MyWindow2Open, Mode=TwoWay}"/>
</i:Interaction.Behaviors>
<Button Content="Open Window 1" Command="{Binding vm:OpenWindow1Command" Margin="10"/>
<Button Content="Open Window 2" Command="{Binding vm:OpenWindow2Command" Margin="10"/>
</Window>