gpt4 book ai didi

wpf - 使用服务定位器的 MVVM 模态对话框

转载 作者:行者123 更新时间:2023-12-04 15:24:15 27 4
gpt4 key购买 nike

我正在开发一个遵循 MVVM 模式的 WPF 应用程序。为了显示模式对话框,我尝试按照以下文章建议的方式进行操作。
http://www.codeproject.com/Articles/36745/Showing-Dialogs-When-Using-the-MVVM-Pattern?fid=1541292&fr=26#xx0xx

但是在这类文章中,我观察到的是,DialogService 接口(interface)的 ShowDialog 方法是从 MainWindowViewModel 调用的。

我的申请中的情况略有不同。
MainWindow.xaml 包含一个用户控件,例如 ChildView,其中包含一个按钮 Add。
MainWindowViewModel 包含另一个 ViewModel,例如 ChildVM,它与 ChildView 绑定(bind)。
ChildVM 包含 AddCommand,我需要在 AddExecute 方法时显示 Modal Dialog
对应于 AddCommand 被调用。
我怎样才能做到这一点?

编辑代码

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

最佳答案

好的,如果我没听错的话,您想不是从 MainWindowViewModel,而是从不同的 ChildViewModel 打开模态对话框?

查看您链接的 CodeProject 文章的 MainWindowViewModel 的构造函数:

ViewModel 有一个具有以下签名的构造函数:

public MainWindowViewModel(
IDialogService dialogService,
IPersonService personService,
Func<IOpenFileDialog> openFileDialogFactory)

这意味着对于构建,您需要显示模式对话框的服务、另一个服务(personService),这在此处无关紧要,以及用于打开文件的特定对话框的工厂,openFileDialogFactory。

为了使用服务,这是本文的核心部分,实现了一个简单的 ServiceLocator 并定义了一个默认构造函数,它使用 ServiceLocator 来获取 ViewModel 需要的服务的实例:

public MainWindowViewModel()
: this(
ServiceLocator.Resolve<IDialogService>(),
ServiceLocator.Resolve<IPersonService>(),
() => ServiceLocator.Resolve<IOpenFileDialog>())
{}

这是可能的,因为 ServiceLocator 是静态的。或者,您可以使用 ServiceLocator 在构造函数中设置服务的本地字段。上述方法更好,因为它允许您自己设置服务,如果您不想使用 ServiceLocator。

您可以在自己的 ChildViewModel 中执行完全相同的操作。

public ChildViewModel(IDialogService dialogService)
{
_dialogService = dialogService;
}

创建一个默认构造函数,它使用从 ServiceLocator 解析的服务实例调用上述构造函数:

public ChildViewModel() : this(ServiceLocator.Resolve<IDialogService>()) {}

现在您可以在 ChildViewModel 中的任何位置使用该服务,如下所示:

_dialogService.ShowDialog<WhateverDialog>(this, vmForDialog);

为了找到您的 View 的所有者窗口,它不是 View 本身,您需要修改 FindOwnerWindow DialogService 的方法来查找 View 的父窗口,而不是将 Window 作为 View 本身。您可以使用 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;
}

您仍然需要注册 UserControl,在 UserControl 上设置附加属性:
<UserControl x:Class="ChildView"
...
Service:DialogService.IsRegisteredView="True">
...
</UserControl>

据我所知,这是可行的。

附加信息:

为了完成同样的事情,我使用了 PRISM 框架,它提供了很多功能来实现这种解耦、控制反转 (IoC) 和依赖注入(inject) (DI)。也许值得为你看看它,也是。

希望这可以帮助!

编辑考虑评论。

关于wpf - 使用服务定位器的 MVVM 模态对话框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15221367/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com