我有一个WPF应用程序,我正在尝试遵守MVVM模式规则。我的一个视图包含按钮:
<Button
Command="{Binding BrowseCommand}"
Margin="50, 0, 0, 0"
Style="{StaticResource CommonButtonStyle}"
Width="100"
Height="30">
<TextBlock
Text="Browse"/>
</Button>
按钮命令调用方法:
private void Browse(object sender)
{
DialogService.BrowseForDestinationPath(DestinationPath);
}
此方法的主要目的是显示“选择目录对话框”,收集数据并将其返回到视图模型。
public static class DialogService
{
public static event Action<string> FolderBrowseRequested;
...
public static void BrowseForDestinationPath(string initialPath)
{
FolderBrowseRequested?.Invoke(initialPath);
}
}
调用我的DialogService类中定义的事件,并且触发位于对话框代码后面的订户方法:
protected void OnFolderBrowseRequested(string initialPath)
{
string destinationPath = initialPath;
var browsingDialog = new VistaFolderBrowserDialog();
if(browsingDialog.ShowDialog(this).GetValueOrDefault())
{
destinationPath = browsingDialog.SelectedPath;
var dataContext = DataContext as UnpackArchiveWindowViewModel;
if (dataContext != null)
dataContext.DestinationPath = destinationPath;
}
DialogService.FolderBrowseRequested -= OnFolderBrowseRequested; //so dumb
}
问题是我真的不喜欢这种解决方案,我坚信它是不必要的复杂和不雅观的。如何在单击按钮时正确显示对话框,收集一些数据并将其交付给我们的视图模型?我想将View和ViewModel分开,并完全尊重MVVM机制。
答案 0 :(得分:0)
您首先可以在界面中描述DialogService所需的行为。
public interface IDialogService
{
void BrowseForDestinationPath(string initialPath);
event PathSelectedEvent PathSelected;
}
public delegate void PathSelectedEvent(string destinationPath);
您的ViewModel将包含IDialogService类型的成员并订阅PathSelectedEvent。将使用您的“浏览”方法(使用“命令”调用)来调用BrowseForDestinationPath方法。
然后可以创建一个实现IDialogService的用户控件。您可以通过ViewModels构造函数或如果ViewModel具有类似
的属性来注入public IDialogService FolderBorwser {get;set;}
这种方法的好处是您的视图模型只知道一个接口。现在,您将创建具体实例的职责委托给其他对象。我建议使用像Unity或MEF这样的注入容器,因为它们可以处理依赖关系的管理和解决。
答案 1 :(得分:0)
我鼓励您编写自己的逻辑,因为它可以帮助您了解在MVVM中打开对话框的问题,但是,如果碰到一堵砖墙或不想采取简单的方法,则会有一个名为{{ 3}}可以帮助您解决这些问题。
使用该库,您将像这样编写代码。
private void Browse(object sender)
{
var settings = new FolderBrowserDialogSettings
{
Description = "This is a description"
};
bool? success = dialogService.ShowFolderBrowserDialog(this, settings);
if (success == true)
{
// Do something with 'settings.SelectedPath'
}
}