如何在使用MVVM的WPF应用程序中使用FolderBrowserDialog
如何在使用MVVM的WPF应用程序中使用FolderBrowserDialog
我正试图从我的WPF应用程序中使用FolderBrowserDialog
- 没什么花哨的。我并不在乎它看起来像Windows Forms。
我找到了一个适当答案的问题(如何在WPF应用程序中使用FolderBrowserDialog),只是我正在使用MVVM。
这个是我“实现”的答案,只是我无法获取窗口对象,我只是调用ShowDialog()
而没有任何参数。
问题是这样的:
var dlg = new FolderBrowserDialog(); System.Windows.Forms.DialogResult result = dlg.ShowDialog(this.GetIWin32Window());
在我的ViewModel
中,this
没有GetIWin32Window()
方法让我获取窗口上下文。
有什么办法让这个工作吗?
问题的出现原因:
在WPF中,使用MVVM模式开发应用程序时,需要在View中使用FolderBrowserDialog对话框来选择文件夹路径。然而,WPF并没有直接提供FolderBrowserDialog控件,而是使用了WinForms中的FolderBrowserDialog控件。因此,需要编写一个自定义的行为(behavior)来实现在WPF应用程序中使用FolderBrowserDialog。
解决方法:
1. 首先,需要创建一个名为FolderDialogBehavior的行为类,继承自Behavior
2. 在OnAttached方法中,将AssociatedObject的Click事件与OnClick方法关联起来。在OnClick方法中,创建一个FolderBrowserDialog实例,并调用其ShowDialog方法显示对话框。
3. 当用户选择了文件夹并点击了对话框中的"确定"按钮时,判断AssociatedObject的DataContext是否为空。如果不为空,则获取DataContext的类型,并使用反射获取与SetterName属性名匹配的属性信息。
4. 最后,使用反射将选中的文件夹路径值设置给ViewModel中对应的属性。
使用示例:
在XAML中,将Button控件与FolderDialogBehavior行为关联,并通过SetterName属性指定ViewModel中用于保存文件夹路径的属性名。
最终,通过上述解决方法,可以在WPF应用程序中使用FolderBrowserDialog对话框,并将选择的文件夹路径保存到ViewModel中的属性中。
参考博文:http://kostylizm.blogspot.ru/2014/03/wpf-mvvm-and-winforms-folder-dialog-how.html
在WPF应用程序中使用MVVM模式时,如何使用FolderBrowserDialog是一个常见的问题。下面是该问题的原因和解决方法。
问题的原因是,WPF应用程序中没有直接使用FolderBrowserDialog的方法。而FolderBrowserDialog是一个Windows Forms控件,与WPF不兼容。因此,需要找到一种方法来在MVVM模式下使用FolderBrowserDialog。
解决方法有两种。第一种方法是使用不需要窗口参数的ShowDialog方法。代码如下:
var dlg = new FolderBrowserDialog(); DialogResult result = dlg.ShowDialog();
第二种方法是将应用程序的主窗口作为FolderBrowserDialog的拥有窗口参数。代码如下:
var dlg = new FolderBrowserDialog(); DialogResult result = dlg.ShowDialog(Application.Current.MainWindow.GetIWin32Window());
第二种方法可能不太符合MVVM模式的规范。可以参考Dr. ABT在这个问题中的答案,通过在ViewModel中注入一个指向View的指针的方式来实现对View的访问。这种技术允许在ViewModel中访问对应的View,如果确实希望将View作为FolderBrowserDialog的拥有者,可以使用这种方法。
此外,还可以定义一个接口并封装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); } [Export(typeof(IFolderBrowserDialog))] [PartCreationPolicy(CreationPolicy.NonShared)] internal class WindowsFormsFolderBrowserDialog : IFolderBrowserDialog { //... } internal static class WindowExtensions { //... } internal class Wpf32Window : System.Windows.Forms.IWin32Window { //... }
在需要使用FolderBrowserDialog的ViewModel/Command中导入IFolderBrowserDialog。在应用程序中,调用IFolderBrowserDialog.ShowDialog方法显示对话框。在单元测试中,可以使用IFolderBrowserDialog的模拟对象来验证调用参数是否正确,或者将所选文件夹返回给SUT以便继续测试。
这样,就可以在WPF应用程序中使用FolderBrowserDialog,并符合MVVM模式的要求。
问题的出现原因:
这个问题的出现是因为在WPF应用程序中使用FolderBrowserDialog时,需要将窗口的句柄传递给FolderBrowserDialog,但是在MVVM模式下,窗口的句柄是无法直接访问的,因此需要找到一种解决方法。
解决方法:
解决方法是通过创建一个依赖属性来公开窗口的句柄,然后将该句柄传递给FolderBrowserDialog。具体步骤如下:
1. 在视图中创建一个依赖属性,用于公开窗口的句柄。
public static readonly DependencyProperty WindowHandleProperty = DependencyProperty.Register("WindowHandle", typeof(System.Windows.Forms.IWin32Window), typeof(MainWindow), new PropertyMetadata(null)); public System.Windows.Forms.IWin32Window WindowHandle { get { return (System.Windows.Forms.IWin32Window)GetValue(WindowHandleProperty); } set { SetValue(WindowHandleProperty, value); } }
2. 在窗口加载时,使用之前链接的问题中提供的扩展方法获取窗口的句柄,并将其绑定到依赖属性上。
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(); }
3. 在ViewModel中创建一个与视图中的依赖属性对应的属性,用于接收窗口的句柄。
private System.Windows.Forms.IWin32Window _windowHandle; public System.Windows.Forms.IWin32Window WindowHandle { get { return _windowHandle; } set { if (_windowHandle != value) { _windowHandle = value; RaisePropertyChanged("WindowHandle"); } } }
这种解决方法的好处是不需要硬编码将一个ViewModel与一个特定的View配对。如果在多个View中使用相同的ViewModel,它应该能正常工作。如果创建了一个新的View但没有实现依赖属性,它将使用null句柄进行操作。
注:
另外需要注意的是,是否测试过不提供IWin32Owner参数的情况?对于我来说,它仍然以应用程序的模态对话框自动打开,并阻止用户与应用程序的所有窗口进行交互。您是否需要它做其他事情呢?