Ani*_*aul 6 wpf modal-dialog mvvm
我正在开发一个遵循MVVM模式的WPF应用程序.要显示模态对话框,我试着按照以下文章建议的方式. http://www.codeproject.com/Articles/36745/Showing-Dialogs-When-Using-the-MVVM-Pattern?fid=1541292&fr=26#xx0xx
但是在这些文章中,我观察到,从MainWindowViewModel调用DialogService接口的ShowDialog方法.
我的申请中的情况略有不同.MainWindow.xaml包含一个用户控件,表示包含按钮Add的ChildView.MainWindowViewModel包含另一个ViewModel,表示与ChildView绑定的ChildVM.ChildVM包含AddCommand,当调用与AddCommand相对应的AddExecute方法时,我需要显示模态对话框.我怎么能做到这一点?
编辑代码
private Window FindOwnerWindow(object viewModel)
{
FrameworkElement view = null;
// Windows and UserControls are registered as view.
// So all the active windows and userControls are contained in views
foreach (FrameworkElement viewIterator in views)
{
// Check whether the view is an Window
// If the view is an window and dataContext of the window, matches
// with the viewModel, then set view = viewIterator
Window viewWindow = viewIterator as Window;
if (null != viewWindow)
{
if (true == ReferenceEquals(viewWindow.DataContext, viewModel))
{
view = viewWindow;
break;
}
}
else
{
// Check whether the view is an UserControl
// If the view is an UserControl and Content of the userControl, matches
// with the viewModel, then set view = userControl
// In case the view is an user control, then find the Window that contains the
// user control and set it as owner
System.Windows.Controls.UserControl userControl = viewIterator as System.Windows.Controls.UserControl;
if (null != userControl)
{
if (true == ReferenceEquals(userControl.Content, viewModel))
{
view = userControl;
break;
}
}
}
}
if (view == null)
{
throw new ArgumentException("Viewmodel is not referenced by any registered View.");
}
// Get owner window
Window owner = view as Window;
if (owner == null)
{
owner = Window.GetWindow(view);
}
// Make sure owner window was found
if (owner == null)
{
throw new InvalidOperationException("View is not contained within a Window.");
}
return owner;
}
Run Code Online (Sandbox Code Playgroud)
好的,如果我没理解错的话,您想不是从 MainWindowViewModel 而是从另一个 ChildViewModel 打开模式对话框?
查看您链接的 CodeProject 文章的 MainWindowViewModel 的构造函数:
ViewModel 有一个具有以下签名的构造函数:
public MainWindowViewModel(
IDialogService dialogService,
IPersonService personService,
Func<IOpenFileDialog> openFileDialogFactory)
Run Code Online (Sandbox Code Playgroud)
这意味着,为了构建,您需要显示模式对话框的服务、另一个服务(personService)(这里无关紧要)以及用于打开文件的特定对话框的工厂 openFileDialogFactory。
为了使用本文的核心部分服务,实现了一个简单的 ServiceLocator 并定义了一个默认构造函数,该构造函数使用 ServiceLocator 来获取 ViewModel 需要的服务的实例:
public MainWindowViewModel()
: this(
ServiceLocator.Resolve<IDialogService>(),
ServiceLocator.Resolve<IPersonService>(),
() => ServiceLocator.Resolve<IOpenFileDialog>())
{}
Run Code Online (Sandbox Code Playgroud)
这是可能的,因为 ServiceLocator 是静态的。或者,您可以使用 ServiceLocator 在构造函数中设置服务的本地字段。上述方法更好,因为如果您不想使用 ServiceLocator,它允许您自己设置服务。
您可以在自己的 ChildViewModel 中执行完全相同的操作。
public ChildViewModel(IDialogService dialogService)
{
_dialogService = dialogService;
}
Run Code Online (Sandbox Code Playgroud)
创建一个默认构造函数,它使用从 ServiceLocator 解析的服务实例调用上述构造函数:
public ChildViewModel() : this(ServiceLocator.Resolve<IDialogService>()) {}
Run Code Online (Sandbox Code Playgroud)
现在您可以从 ChildViewModel 中的任何位置使用该服务,如下所示:
_dialogService.ShowDialog<WhateverDialog>(this, vmForDialog);
Run Code Online (Sandbox Code Playgroud)
为了找到视图的所有者窗口(它不是视图本身),您需要修改FindOwnerWindowDialogService 的方法来查找视图的父窗口,而不是期望 Window 作为视图本身。您可以使用 VisualTreeHelper 来执行此操作:
private Window FindOwnerWindow(object viewModel)
{
var view = views.SingleOrDefault(v => ReferenceEquals(v.DataContext, viewModel));
if (view == null)
{
throw new ArgumentException("Viewmodel is not referenced by any registered View.");
}
DependencyObject owner = view;
// Iterate through parents until a window is found,
// if the view is not a window itself
while (!(owner is Window))
{
owner = VisualTreeHelper.GetParent(owner);
if (owner == null)
throw new Exception("No window found owning the view.");
}
// Make sure owner window was found
if (owner == null)
{
throw new InvalidOperationException("View is not contained within a Window.");
}
return (Window) owner;
}
Run Code Online (Sandbox Code Playgroud)
不过,您仍然需要注册 UserControl,在 UserControl 上设置附加属性:
<UserControl x:Class="ChildView"
...
Service:DialogService.IsRegisteredView="True">
...
</UserControl>
Run Code Online (Sandbox Code Playgroud)
据我所知,这是可行的。
附加信息:
为了完成同样的事情,我使用 PRISM 框架,该框架提供了许多用于此类解耦、控制反转 (IoC) 和依赖注入 (DI) 的功能。也许您也值得一看。
希望这可以帮助!
编辑以考虑该评论。
| 归档时间: |
|
| 查看次数: |
4723 次 |
| 最近记录: |