Give some command to View in MVVM

前端 未结 5 1849
伪装坚强ぢ
伪装坚强ぢ 2020-11-28 23:07

Let\'s imagine I have some user control. The user control has some child windows. And user control user wants to close child windows of some type. There is a method in user

5条回答
  •  失恋的感觉
    2020-11-28 23:33

    I feel I just found a rather nice MVVM solution to this problem. I wrote a behavior that is exposing a type property WindowType and a boolean property Open. DataBinding the latter allows the ViewModel to open and close the windows easily, without knowing anything about the View.

    Gotta love behaviors... :)

    enter image description here

    Xaml:

    
    
        
            
        
        
            
            
            
            
        
        
            5
            
            
        
    
        
            
                
                    
                    

    YellowWindow (Black/Purple alike):

    
        
    
    

    ViewModel, ActionCommand:

    using System;
    using System.ComponentModel;
    using System.Windows.Input;
    
    namespace WpfApplication1
    {
        public class ViewModel : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            private void OnPropertyChanged(string propertyName)
            {
                if (this.PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
    
            private bool _blackOpen;
            public bool BlackOpen { get { return _blackOpen; } set { _blackOpen = value; OnPropertyChanged("BlackOpen"); } }
    
            private bool _yellowOpen;
            public bool YellowOpen { get { return _yellowOpen; } set { _yellowOpen = value; OnPropertyChanged("YellowOpen"); } }
    
            private bool _purpleOpen;
            public bool PurpleOpen { get { return _purpleOpen; } set { _purpleOpen = value; OnPropertyChanged("PurpleOpen"); } }
    
            public ICommand OpenBlackCommand { get; private set; }
            public ICommand OpenYellowCommand { get; private set; }
            public ICommand OpenPurpleCommand { get; private set; }
    
    
            public ViewModel()
            {
                this.OpenBlackCommand = new ActionCommand(OpenBlack);
                this.OpenYellowCommand = new ActionCommand(OpenYellow);
                this.OpenPurpleCommand = new ActionCommand(OpenPurple);
            }
    
            private void OpenBlack(bool open) { this.BlackOpen = open; }
            private void OpenYellow(bool open) { this.YellowOpen = open; }
            private void OpenPurple(bool open) { this.PurpleOpen = open; }
    
        }
    
        public class ActionCommand : ICommand
        {
            public event EventHandler CanExecuteChanged;
            private Action _action;
    
            public ActionCommand(Action action)
            {
                _action = action;
            }
    
            public bool CanExecute(object parameter) { return true; }
    
            public void Execute(object parameter)
            {
                if (_action != null)
                {
                    var castParameter = (T)Convert.ChangeType(parameter, typeof(T));
                    _action(castParameter);
                }
            }
        }
    }
    

    OpenCloseWindowBehavior:

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Interactivity;
    
    namespace WpfApplication1
    {
        public class OpenCloseWindowBehavior : Behavior
        {
            private Window _windowInstance;
    
            public Type WindowType { get { return (Type)GetValue(WindowTypeProperty); } set { SetValue(WindowTypeProperty, value); } }
            public static readonly DependencyProperty WindowTypeProperty = DependencyProperty.Register("WindowType", typeof(Type), typeof(OpenCloseWindowBehavior), new PropertyMetadata(null));
    
            public bool Open { get { return (bool)GetValue(OpenProperty); } set { SetValue(OpenProperty, value); } }
            public static readonly DependencyProperty OpenProperty = DependencyProperty.Register("Open", typeof(bool), typeof(OpenCloseWindowBehavior), new PropertyMetadata(false, OnOpenChanged));
    
            /// 
            /// Opens or closes a window of type 'WindowType'.
            /// 
            private static void OnOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                var me = (OpenCloseWindowBehavior)d;
                if ((bool)e.NewValue)
                {
                    object 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.Show();
                        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
                }
            }
        }
    }
    

提交回复
热议问题