jkmills78
2/20/2017 - 6:08 PM

Interactivity - Open Views from ViewModel

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>