How to use FolderBrowserDialog from a WPF application with MVVM

I am trying to use FolderBrowserDialogWPF from my application - nothing unusual. I don't care that Windows Forms is accessing it.

I found a question with a suitable answer ( How to use FolderBrowserDialog from a WPF application ), except that I am using MVVM.

This was the answer that I “implemented”, except that I can’t get the window object, and I just callShowDialog()without any parameters.

The problem is this:

var dlg = new FolderBrowserDialog();
System.Windows.Forms.DialogResult result = dlg.ShowDialog(this.GetIWin32Window());

In mine ViewModelthere thisis no method GetIWin32Window()for me to get the window context.

Any ideas on how to make this work?

+5
5

ShowDialog, .

var dlg = new FolderBrowserDialog();
DialogResult result = dlg.ShowDialog();

-, .

var dlg = new FolderBrowserDialog();
DialogResult result = dlg.ShowDialog(Application.Current.MainWindow.GetIWin32Window());

MVVMish.

. @. ABT ViewModel ( , , ). , , FolderBrowserDialog.

@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
  }

VM/Command, FolderBrowser IFolderBrowserDialog. IFolderBrowserDialog.ShowDialog . unit test IFolderBrowserDialog, , / sut, .

+4

FolderBrowserDialog, .

DependencyProperty , .

public static readonly DependencyProperty WindowHandleProperty =
    DependencyProperty.Register("WindowHandle", typeof(System.Windows.Forms.IWin32Window), typeof(MainWindow), new PropertyMetadata(null));

// MainWindow.cs
public System.Windows.Forms.IWin32Window WindowHandle
{
    get { return (System.Windows.Forms.IWin32Window)GetValue(WindowHandleProperty); }
    set { SetValue(WindowHandleProperty, value); }
}

, , , , , :

// MainWindow.cs
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    var binding = new Binding();
    binding.Path = new PropertyPath("WindowHandle");
    binding.Mode = BindingMode.OneWayToSource;
    SetBinding(WindowHandleProperty, binding);

    WindowHandle = this.GetIWin32Window();
}

, , WindowHandle. , ViewModel WindowHandle, IWin32Handle :

// ViewModel.cs
private System.Windows.Forms.IWin32Window _windowHandle; 
public System.Windows.Forms.IWin32Window WindowHandle
{
    get
    {
        return _windowHandle;
    }
    set
    {
        if (_windowHandle != value)
        {
            _windowHandle = value;
            RaisePropertyChanged("WindowHandle");
        }
    }
}

, ViewModel . ViewModel, . , DependencyProperty, .

EDIT:

, , IWin32Owner? - . - , ?

+2

MVVM:

FolderBrowserDialog. . ( FolderBrowserDialog).

, MVVM , .

0

mvvm, Dialog-Service. .

mvvm . . , .

if you use dependency injection for a service (interface), you get the advantage so that you can test the solution while taunting. Or you can replace the forms folderbrowserdialog if there is wpf.

0
source

MVVM + WinForms FolderBrowserDialog as behavior

public class FolderDialogBehavior : Behavior<Button>
{
    public string SetterName { get; set; }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Click += OnClick;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.Click -= OnClick;
    }

    private void OnClick(object sender, RoutedEventArgs e)
    {
        var dialog = new FolderBrowserDialog();
        var result = dialog.ShowDialog();
        if (result == DialogResult.OK && AssociatedObject.DataContext != null)
        {
            var propertyInfo = AssociatedObject.DataContext.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(p => p.CanRead && p.CanWrite)
            .Where(p => p.Name.Equals(SetterName))
            .First();

            propertyInfo.SetValue(AssociatedObject.DataContext, dialog.SelectedPath, null);
        }
    }
}

Using

     <Button Grid.Column="3" Content="...">
            <Interactivity:Interaction.Behaviors>
                <Behavior:FolderDialogBehavior SetterName="SomeFolderPathPropertyName"/>
            </Interactivity:Interaction.Behaviors>
     </Button>

Blogpost: http://kostylizm.blogspot.ru/2014/03/wpf-mvvm-and-winforms-folder-dialog-how.html

0
source

All Articles