如何使用MVVM的WPF应用程序中的FolderBrowserDialog

Dav*_*ork 5 .net c# wpf folderbrowserdialog mvvm

我正在尝试使用FolderBrowserDialog我的WPF应用程序 - 没什么特别的.我不太关心它有Windows窗体的外观.

我找到了一个问题,其中包含一个合适的答案(如何使用WPF应用程序中的FolderBrowserDialog),除了我正在使用MVVM.

是我"实现"的答案,除了我无法获取窗口对象,我只是在ShowDialog()没有任何参数的情况下调用.

问题是这样的:

var dlg = new FolderBrowserDialog();
System.Windows.Forms.DialogResult result = dlg.ShowDialog(this.GetIWin32Window());
Run Code Online (Sandbox Code Playgroud)

在我的ViewModel那里,this没有GetIWin32Window()方法让我获得Window上下文.

关于如何使这项工作的任何想法?

wag*_*ghe 4

首先,您可以使用不需要窗口的 ShowDialog 签名。

var dlg = new FolderBrowserDialog();
DialogResult result = dlg.ShowDialog();
Run Code Online (Sandbox Code Playgroud)

其次,您可以将应用程序的主窗口作为所属窗口发送。

var dlg = new FolderBrowserDialog();
DialogResult result = dlg.ShowDialog(Application.Current.MainWindow.GetIWin32Window());
Run Code Online (Sandbox Code Playgroud)

第二个选项可能不被认为是非常 MVVMish。

请参阅@ABT博士这个问题中的答案,了解将指向视图的指针注入到视图模型中的方法(不确定这是一个好主意还是坏主意,但我不会让这阻止我)通过这种技术,如果您确实想让该视图成为FolderBrowserDialog 的所有者,您就可以在VM 中访问相应的视图。

@ChrisDD 关于定义接口和包装FolderBrowserDialog 是正确的。我们就是这样做的:

  public interface IFolderBrowserDialog
  {
    string Description { get; set; }
    Environment.SpecialFolder RootFolder { get; set; }
    string SelectedPath { get; set; }
    bool ShowNewFolderButton { get; set; }
    bool? ShowDialog();
    bool? ShowDialog(Window owner);
  }

  //Decorated for MEF injection
  [Export(typeof(IFolderBrowserDialog))]
  [PartCreationPolicy(CreationPolicy.NonShared)]
  internal class WindowsFormsFolderBrowserDialog : IFolderBrowserDialog
  {
    private string _description;
    private string _selectedPath;

    [ImportingConstructor]
    public WindowsFormsFolderBrowserDialog()
    {
      RootFolder = System.Environment.SpecialFolder.MyComputer;
      ShowNewFolderButton = false;
    }

    #region IFolderBrowserDialog Members

    public string Description
    {
      get { return _description ?? string.Empty; }
      set { _description = value; }
    }

    public System.Environment.SpecialFolder RootFolder { get; set; }

    public string SelectedPath
    {
      get { return _selectedPath ?? string.Empty; }
      set { _selectedPath = value; }
    }

    public bool ShowNewFolderButton { get; set; }

    public bool? ShowDialog()
    {
      using (var dialog = CreateDialog())
      {
        var result = dialog.ShowDialog() == DialogResult.OK;
        if (result) SelectedPath = dialog.SelectedPath;
        return result;
      }
    }

    public bool? ShowDialog(Window owner)
    {
      using (var dialog = CreateDialog())
      {
        var result = dialog.ShowDialog(owner.AsWin32Window()) == DialogResult.OK;
        if (result) SelectedPath = dialog.SelectedPath;
        return result;
      }
    }
    #endregion

    private FolderBrowserDialog CreateDialog()
    {
      var dialog = new FolderBrowserDialog();
      dialog.Description = Description;
      dialog.RootFolder = RootFolder;
      dialog.SelectedPath = SelectedPath;
      dialog.ShowNewFolderButton = ShowNewFolderButton;
      return dialog;
    }
  }

  internal static class WindowExtensions
  {
    public static System.Windows.Forms.IWin32Window AsWin32Window(this Window window)
    {
      return new Wpf32Window(window);
    }
  }

  internal class Wpf32Window : System.Windows.Forms.IWin32Window
  {
    public Wpf32Window(Window window)
    {
      Handle = new WindowInteropHelper(window).Handle;
    }

    #region IWin32Window Members

    public IntPtr Handle { get; private set; }

    #endregion
  }
Run Code Online (Sandbox Code Playgroud)

然后我们在要使用FolderBrowser的地方创建VM/Command,导入IFolderBrowserDialog。在应用程序中,IFolderBrowserDialog.ShowDialog 显示对话框。在单元测试中,我们模拟 IFolderBrowserDialog,以便我们可以验证它是否使用正确的参数调用和/或将选定的文件夹发送回 sut,以便测试可以继续。