c# - 谁拥有 Message Box、View 或 ViewModel?

标签 c# wpf mvvm mahapps.metro

我正在使用 Mahapps.Metro 开发 WPF 应用程序,Mahapps.Metro 是一个提供“现代”UI 样式的 Nuget 包。

我创建了一个对话框,它是那些选择对话框之一,您可以在其中选择左侧的项目,单击向右箭头按钮,然后该项目将移动到右侧。

我的对话框中的验证规则之一是在您按下按钮之前至少必须选择一个项目,因此(在我 View 的代码隐藏中)我打开一个消息框并通知用户如果他没有t 选择至少一项:

private void AddButton_Click(object sender, RoutedEventArgs e)
{
    if (!IsAnySelected(Users))
    {
        // MetroWindow call
        this.ShowMessageAsync("Permissions", "Please select a User.");
        return;

        // Call ViewModel `AddPermissions()` method here.
    }
}

bool IsAnySelected(DataGrid dataGrid)
{
    foreach(dynamic d in dataGrid.ItemsSource)
    { 
        if (d.IsSelected) return true;
    }
    return false;
}

(DataGrid 绑定(bind)到 ViewModel 中的 ObservableCollection)

由于 WPF 中的普通消息框没有样式,Mahapps 提供了自己的样式。正是在这里,我发现当我尝试在我的 View 中打开一个消息框时,MahApps 会抛出一个空引用异常。这与我的设置有关,因为他们的演示效果很好。

原来有人提供了打开Mahapps消息框的方法in the View Model instead of the view. 我的问题是,你为什么要这样做?

View 是否不对任何视觉元素(包括消息框)负责,验证不是 View 的代码隐藏中允许做的一件事吗?

请注意,这种方法会导致新问题,即您现在需要一种方法来 fire the View Model's method or ICommand from CodeBehind :

(DataContext as SecurityDialogViewModel).AddPermissions();

最佳答案

我一直采用通过回调接口(interface)公开用户对话框的方法。 OpenFileDialog、SaveFileDialog、MessageBox、FolderSelectionDialog 等由接口(interface)定义:

public interface IMainViewCallbacks
{
        bool GetPathViaOpenDialog(out string filePath, string szFilter, 
                 string szDefaultExt, string szInitialDir);
        bool GetPathViaSaveDialog(out string filePath, string szFilter, 
                 string szDefaultExt, string szInitialDir);
        bool GetFolderPath(out string folderPath);
        MessageBoxResult MessageBox(string messageBoxText, string caption, 
                  MessageBoxButton button, MessageBoxImage icon);
}

然后,在 View 代码隐藏中实现接口(interface)。

在 View 构造器中创建 View 模型时,传递this:

public class MainViewMode : IMainViewCallbacks
{
   private vm = null;
   public MainWindow()
   {
      vm = new MainViewModel(this);
      this.DataContext = vm;
   }
}

最后,向您的 View 模型构造函数添加一个参数以接收接口(interface):

public class MainViewModel
{
    IMainViewCallbacks Calllbacks = null;
    public MainViewModel(IMainViewCallbacks cb)
    {
       // stash the callbacks for later.
       this.Callbacks = cb;
    }

    // pseudocode for the command that consumes the callback
    public ICommand .... 
    {
        Execute() { this.Callbacks.GetPathViaOpenDialog(); }
    } 
}

这是单元可测试的;单元测试 View 提供的接口(interface)可以假装接收到用户输入并只返回一个常量值。

关于c# - 谁拥有 Message Box、View 或 ViewModel?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48836153/

相关文章:

c# - C# 中的(普通)throw 语句会导致异常吗?

c# - 为什么调用构造函数而不是给我一个错误?

C#/WPF 文本框错误 : "Value ' ' cannot be converted", TargetNull 不工作

c# - 忽略 C# 中的接口(interface)方法实现

c# - 将并发字典保存线程不安全的集合是否需要在C#中锁定

wpf - MVVM WPF - ItemsControl 内的 ComboBox 双向绑定(bind)

c# - RibbonControlsLibrary - 如何禁用最小化?

.net - 我的列表框中的项目之间的差距

c# - PropertyChangedEventHandler 和 NotifyCollectionChangedEventHandler 有什么区别?

c# - WPF 用户控件的多个实例都使用相同的 ViewModel