题
好吧,我真的想知道如何的专家。开发商处理的一个->打开文件的对话在WPF.
我真的不想这样做在我的视图模型(其中"浏览"中引用,通过一个DelegateCommand)
void Browse(object param)
{
//Add code here
OpenFileDialog d = new OpenFileDialog();
if (d.ShowDialog() == true)
{
//Do stuff
}
}
因为我认为,违反。方法。
我做什么?
解决方案
在这里做的最好的事情是使用服务。
一个服务就是您从服务的中央存储库,通常是IOC容器访问类。然后,服务实现你所需要的像打开文件对话框。
因此,假设你有一个团结容器中的IFileDialogService
,你可以做...
void Browse(object param)
{
var fileDialogService = container.Resolve<IFileDialogService>();
string path = fileDialogService.OpenFileDialog();
if (!string.IsNullOrEmpty(path))
{
//Do stuff
}
}
其他提示
我也喜欢上了一个答案发表评论,但很可惜,我的名声不够高这样做。
具有呼叫诸如打开文件对话框(),因为它意味着在视图模型的视图(对话)违反MVVM模式。视图模型可以调用像用GetFileName()(也就是说,如果简单的绑定是不够的),但它不应该关心如何获得文件名。
我使用的我例如可以传递到我的视图模型的构造或者通过依赖注入解决服务。 e.g。
public interface IOpenFileService
{
string FileName { get; }
bool OpenFileDialog()
}
和一个类实现它,在引擎盖下使用的OpenFileDialog。在视图模型,我只使用该接口,因此可以模拟/如果需要更换。
在视图模型不应该打开的对话框,甚至不知道它们的存在。如果VM被容纳在一个单独的DLL,该项目应不必PresentationFramework的参考。
我喜欢在通用对话框视图使用一个辅助类。
在助手类暴露该窗口结合在XAML的命令(而不是一个事件)。这意味着在视图中使用RelayCommand的。助手类是DepencyObject因此它可以绑定到视图模型
class DialogHelper : DependencyObject
{
public ViewModel ViewModel
{
get { return (ViewModel)GetValue(ViewModelProperty); }
set { SetValue(ViewModelProperty, value); }
}
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel", typeof(ViewModel), typeof(DialogHelper),
new UIPropertyMetadata(new PropertyChangedCallback(ViewModelProperty_Changed)));
private static void ViewModelProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (ViewModelProperty != null)
{
Binding myBinding = new Binding("FileName");
myBinding.Source = e.NewValue;
myBinding.Mode = BindingMode.OneWayToSource;
BindingOperations.SetBinding(d, FileNameProperty, myBinding);
}
}
private string FileName
{
get { return (string)GetValue(FileNameProperty); }
set { SetValue(FileNameProperty, value); }
}
private static readonly DependencyProperty FileNameProperty =
DependencyProperty.Register("FileName", typeof(string), typeof(DialogHelper),
new UIPropertyMetadata(new PropertyChangedCallback(FileNameProperty_Changed)));
private static void FileNameProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Debug.WriteLine("DialogHelper.FileName = {0}", e.NewValue);
}
public ICommand OpenFile { get; private set; }
public DialogHelper()
{
OpenFile = new RelayCommand(OpenFileAction);
}
private void OpenFileAction(object obj)
{
OpenFileDialog dlg = new OpenFileDialog();
if (dlg.ShowDialog() == true)
{
FileName = dlg.FileName;
}
}
}
在助手类需要视图模型实例的引用。请参见资源字典。刚施工后,视图模型属性设置(在同一行的XAML)。这是当在辅助类FileName属性绑定到上视图模型FileName属性。
<Window x:Class="DialogExperiment.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DialogExperiment"
xmlns:vm="clr-namespace:DialogExperimentVM;assembly=DialogExperimentVM"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<vm:ViewModel x:Key="viewModel" />
<local:DialogHelper x:Key="helper" ViewModel="{StaticResource viewModel}"/>
</Window.Resources>
<DockPanel DataContext="{StaticResource viewModel}">
<Menu DockPanel.Dock="Top">
<MenuItem Header="File">
<MenuItem Header="Open" Command="{Binding Source={StaticResource helper}, Path=OpenFile}" />
</MenuItem>
</Menu>
</DockPanel>
</Window>
有一个服务就像是从视图模型开放的图。 我在视图中的依赖属性,并在属性的chnage,我打开的FileDialog和读取的路径,更新所述VM的性能,并因此绑定属性
我已经解决了它对我来说是这样的:
- 在 视图模型 我有定义的一个接口,并与它的工作在 视图模型
- 在 看 我已经实现这个接口。
CommandImpl没有实现在代码如下。
视图模型:
namespace ViewModels.Interfaces
{
using System.Collections.Generic;
public interface IDialogWindow
{
List<string> ExecuteFileDialog(object owner, string extFilter);
}
}
namespace ViewModels
{
using ViewModels.Interfaces;
public class MyViewModel
{
public ICommand DoSomeThingCmd { get; } = new CommandImpl((dialogType) =>
{
var dlgObj = Activator.CreateInstance(dialogType) as IDialogWindow;
var fileNames = dlgObj?.ExecuteFileDialog(null, "*.txt");
//Do something with fileNames..
});
}
}
观点:
namespace Views
{
using ViewModels.Interfaces;
using Microsoft.Win32;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
public class OpenFilesDialog : IDialogWindow
{
public List<string> ExecuteFileDialog(object owner, string extFilter)
{
var fd = new OpenFileDialog();
fd.Multiselect = true;
if (!string.IsNullOrWhiteSpace(extFilter))
{
fd.Filter = extFilter;
}
fd.ShowDialog(owner as Window);
return fd.FileNames.ToList();
}
}
}
键
<Window
xmlns:views="clr-namespace:Views"
xmlns:viewModels="clr-namespace:ViewModels"
>
<Window.DataContext>
<viewModels:MyViewModel/>
</Window.DataContext>
<Grid>
<Button Content = "Open files.." Command="{Binding DoSomeThingCmd}" CommandParameter="{x:Type views:OpenFilesDialog}"/>
</Grid>
</Window>