在MVVM中给出一些查看的命令。

10 浏览
0 Comments

在MVVM中给出一些查看的命令。

假设我有一个用户控件,该用户控件有一些子窗口。用户控件用户想要关闭某种类型的子窗口。用户控件的代码后台有一个方法:

public void CloseChildWindows(ChildWindowType type)
{
   ...
}

但是由于我无法直接访问视图,所以无法调用此方法。

我考虑的另一个解决方法是以某种方式将用户控件的ViewModel公开为其属性(这样我就可以将其绑定并直接给ViewModel发送命令)。但我不希望用户控件用户知道任何有关用户控件ViewModel的信息。

那么什么是解决这个问题的正确方法?

0
0 Comments

问题的原因是作者发现了一种较好的MVVM解决方案,可以通过使用行为(Behavior)来打开和关闭窗口,而不需要ViewModel知道任何关于View的信息。

解决方法是编写一个行为(Behavior),该行为公开了一个类型属性WindowType和一个布尔属性Open。将后者进行数据绑定可以使ViewModel轻松地打开和关闭窗口,而无需了解View的任何信息。

这种解决方案的优点是可以在XAML中设置窗口的属性,而不需要在ViewModel中暴露这些属性,从而实现了ViewModel和View的解耦。

以下是代码示例:

Xaml:


    
        
    
    
        
        
        
        
    
    
        5
        
        
    
    
        
            
                
                

ViewModel:

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));
        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
            }
        }
    }
}

以上是一个使用MVVM模式实现的窗口打开和关闭功能的示例。通过使用行为(Behavior),ViewModel可以轻松地控制窗口的打开和关闭,而不需要了解View的细节。这种解决方案能够实现ViewModel和View的解耦,提高代码的可维护性和可扩展性。

0
0 Comments

在MVVM中查看视图的问题是如何在ViewModel中处理窗口的打开和关闭。作者提出了使用WindowManager和WindowViewModel的概念来解决这个问题。WindowManager是一个管理窗口的类,而WindowViewModel是每个窗口的ViewModel。

WindowManager类有一个VisibleWindows属性,它是一个ObservableCollection,用于存储当前可见的窗口。当VisibleWindows集合发生变化时,WindowManager类会触发OnVisibleWindowsChanged事件,处理被移除的窗口和被添加的窗口。

WindowViewModel类实现了INotifyPropertyChanged接口,它有一个IsOpen属性,用于表示窗口是否打开。当IsOpen属性发生变化时,WindowViewModel类会通知WindowManager类,以便管理窗口的打开和关闭。

作者指出,这只是一个简单的示例,实际使用时需要根据具体需求进行调整。

总结起来,解决在MVVM中查看视图的问题的方法是使用WindowManager和WindowViewModel的概念来管理窗口的打开和关闭。WindowManager类负责管理可见的窗口集合,而WindowViewModel类负责表示窗口的打开状态,并通知WindowManager类进行相应的处理。这种方法在作者过去的经验中曾经使用过,并且在实际应用中证明是有效的。

0
0 Comments

问题的出现原因是在MVVM模式中,有时候需要从ViewModel中进行页面导航的操作,但是在MVVM中,ViewModel是不能直接访问View的,因此需要找到一种方法来实现从ViewModel中进行页面导航的功能。

解决方法是创建一个导航服务(NavigationService),在该服务中注册View,并通过该服务来进行页面导航操作。具体的实现步骤如下:

1. 创建一个NavigationService类,该类包含一个私有的Window变量_a,用于存储View的引用。

2. 在NavigationService中添加一个RegisterViewA方法,用于注册View。

3. 在NavigationService中添加一个CloseWindowA方法,用于关闭View。

4. 在ViewModel中通过获取NavigationService的实例来进行页面导航操作。

为了获取NavigationService的实例,可以在其上面进行抽象,创建一个INavigationService接口,并通过IoC容器进行注册和获取。更进一步,可以创建两个抽象接口,一个用于注册方法(供View使用),另一个用于导航方法(供ViewModel使用)。

总结一下,使用MVVM模式进行页面导航时,可以通过创建一个导航服务,并在其中注册和关闭View来实现从ViewModel中进行页面导航的操作。通过在导航服务上进行抽象和使用IoC容器,可以更好地实现解耦和可扩展性。

0