【问题标题】:Is ViewModel allowed to close the window?ViewModel 是否允许关闭窗口?
【发布时间】:2013-05-19 03:06:32
【问题描述】:

最近我回答了一个问题How to Bind to window's close button the X-button,我认为这是一个 MVVM 解决方案。请不要专注于那里的实际问题,因为那不是困扰我的事情。我什至不会使用我的解决方案在那种特殊情况下。我肯定会使用@ChrisW 的解决方案。

然后出现了来自@SpikeX 的回复,现在我很困惑。但我必须为此感谢他。我不能停止思考这个问题,因为直到现在我可能还在以错误的方式思考 MVVM。

于是我开始研究:

Close Window from ViewModel

Basic concepts of MVVM— what should a ViewModel do?

等等……

如您所见,我不是宇宙中唯一一个关闭ViewModel 窗口的人。但我真的可以这样做吗?或者我真的不应该在ViewModel 中使用窗口。 MVVM 对这个真的那么严格吗?我的解决方案真的打破了 MVVM 模式吗?

【问题讨论】:

    标签: wpf mvvm design-patterns


    【解决方案1】:

    好吧,在我看来,视图模型应该与使用它的客户端技术完全隔离。

    由于您在实际的 Window 实例上调用 close 方法,因此您需要对特定于客户端的程序集(在本例中为 WPF)的引用,这几乎使得无法将该视图模型重用于其他任何事情。

    如果您想同时制作 WPF、Silverlight、Windows Phone、Windows Store App 等客户端,您将没有机会为它们都使用相同的视图模型,因为 Windows Phone 可能不知道 WPF 窗口是什么是。

    此外,当您在其中引用实际视图元素时,单元测试视图模型会变得更加麻烦。

    因此,您可以在某种视图适配器中将其抽象出来,而不是直接引用窗口。

    如果视图模型只知道这样的接口:

    public interface IView
    {
        void Show();
        void Close();
    }
    

    ...您的每个客户端都可以创建自己的实现,并将其注入到视图模型中,以便在任何给定客户端上执行正确的操作。

    关键是视图模型不知道实际视图。一切都隐藏在接口的实现中。

    【讨论】:

      【解决方案2】:

      嗯,是的,您的解决方案正在打破常规。最大的缺点是,您无法完全测试 VM 和逻辑,这会干扰窗口的关闭。但与往常一样,您必须考虑是否值得努力实施解决方法。

      所以如果你真的想坚持使用 MVVM,你可以使用我在第一个链接 SO post 中发布的解决方案。我在这里复制了我帖子的重要部分。

      引用

      <Window x:Class="AC.Frontend.Controls.DialogControl.Dialog"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:DialogControl="clr-namespace:AC.Frontend.Controls.DialogControl" 
              xmlns:hlp="clr-namespace:AC.Frontend.Helper"
              MinHeight="150" MinWidth="300" ResizeMode="NoResize" SizeToContent="WidthAndHeight"
              WindowStartupLocation="CenterScreen" Title="{Binding Title}"
              hlp:AttachedProperties.DialogResult="{Binding DialogResult}" WindowStyle="ToolWindow" ShowInTaskbar="True"
              Language="{Binding UiCulture, Source={StaticResource Strings}}">
              <!-- A lot more stuff here -->
      </Window>
      

      如您所见,我先声明命名空间xmlns:hlp="clr-namespace:AC.Frontend.Helper",然后再声明绑定hlp:AttachedProperties.DialogResult="{Binding DialogResult}"

      [...]

      public class AttachedProperties
      {
          #region DialogResult
      
          public static readonly DependencyProperty DialogResultProperty =
              DependencyProperty.RegisterAttached("DialogResult", typeof (bool?), typeof (AttachedProperties), new PropertyMetadata(default(bool?), OnDialogResultChanged));
      
          private static void OnDialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
          {
              var wnd = d as Window;
              if (wnd == null)
                  return;
      
              wnd.DialogResult = (bool?) e.NewValue;
          }
      
          public static bool? GetDialogResult(DependencyObject dp)
          {
              if (dp == null) throw new ArgumentNullException("dp");
      
              return (bool?)dp.GetValue(DialogResultProperty);
          }
      
          public static void SetDialogResult(DependencyObject dp, object value)
          {
              if (dp == null) throw new ArgumentNullException("dp");
      
              dp.SetValue(DialogResultProperty, value);
          }
      
          #endregion
      }
      

      /引用

      您唯一需要的就是像这样的VM 来使我的解决方案发挥作用。

      public class WindowVm : ViewModelBase // base class implementing INotifyPropertyChanged
      {
          private bool? _dialogResult;
          public bool? DialogResult
          {
              get { return _dialogResult; }
              set 
              {
                   _dialogResult = value;
                   RaisePropertyChanged(() => DialogResult);
              }
          }
      
          //... many other properties
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-03
        • 2017-04-11
        • 1970-01-01
        • 1970-01-01
        • 2010-12-03
        • 2013-09-05
        • 2012-02-06
        • 2016-09-04
        相关资源
        最近更新 更多