所有,我想知道使用MVVM模式从WPF启动[子]对话框/窗口的公认最佳方法/行业标准。我遇到过以下文章:
一个。 CodeProject - Showing Dialogs When Using the MVVM Pattern
这种做法看起来不错,但对我来说太过分了。这是一定程度的代码复制,我不相信这是正确的方法。
B中。 WPF MVVM and Showing Dialogs
这简要介绍了三个选项,其中包含各种链接,这些链接在解释方法或主题方面都相当/非常差。
有人可以提供使用MVVM从WPF应用程序启动对话框的行业标准方法/方法的解释,最好是一些链接到进一步的阅读材料吗?如果你能自己提供一个例子我当然会非常感激!
感谢您的时间。
答案 0 :(得分:8)
首先,我不知道使用MVVM显示对话框的任何“行业标准”方式,因为没有这样的东西。
其次,欢迎来到MVVM,您刚才谈到了MVVM没有标准的领域
说实话,MVVM有很多痛点,这就是为什么有很多MVVM框架的原因,仅举几个MVVM Light,PRISM,Caliburn.Micro,Cinch,Catel,WAF,Baboon,shell i停止或你想要更多。
现在回答你的问题,在处理了大部分框架之后,我注意到了一个共性,他们都使用了DI / IoC容器然后为你提供了一个接口,比如IDialogManager和他们自己的实现,然后他们问你在视图模型中接受此接口并使用它来显示对话框。总结一下,我会使用依赖注入,有一个显示对话框的界面,然后提供和实现它,并将其注册到di容器,然后从我的视图模型或视图中使用它。
修改:所以你选择PRISM (在我看来)在显示对话框之间最难。现在除此之外,使用Interaction Requests (查看文章中间部分)是很难的方法,或者您可以使用此Answer作为更快的方式。< / p>
答案 1 :(得分:2)
最近,我为WPF实现了自己的导航服务,它使用了Caliburn.Micro的WindowManager(但你可以用别的东西替换它)。
示例(如何使用):
_navigationService.GetWindow<ClientDetailsViewModel>()
.WithParam(vm => vm.IsEditing, true)
.WithParam(vm => vm.Client, SelectedClient)
.DoIfSuccess(() => RefreshSelectedClient())
.ShowWindowModal();
<强>实施强>
namespace ClientApplication.Utilities
{
public class NavigationService : INavigationService
{
SimpleContainer _container;
IWindowManager _windowManager;
public NavigationService(SimpleContainer container, IWindowManager windowManager)
{
_container = container;
_windowManager = windowManager;
}
public INavigationService<TViewModel> GetWindow<TViewModel>()
{
return new NavigationService<TViewModel>(_windowManager, (TViewModel)_container.GetInstance(typeof(TViewModel), null));
}
}
public class NavigationService<TVM> : INavigationService<TVM>
{
IWindowManager _windowManager;
TVM _viewModel;
System.Action _action;
public NavigationService(IWindowManager windowManager, TVM viewModel)
{
_windowManager = windowManager;
_viewModel = viewModel;
}
public INavigationService<TVM> WithParam<TProperty>(Expression<Func<TVM, TProperty>> property, TProperty value)
{
var prop = (PropertyInfo)((MemberExpression)property.Body).Member;
prop.SetValue(_viewModel, value, null);
return this;
}
public INavigationService<TVM> DoBeforeShow(Action<TVM> action)
{
action(_viewModel);
return this;
}
public INavigationService<TVM> DoIfSuccess(System.Action action)
{
_action = action;
return this;
}
public void ShowWindow(IDictionary<string, object> settings = null)
{
_windowManager.ShowWindow(_viewModel, null, settings);
}
public bool ShowWindowModal(IDictionary<string, object> settings = null)
{
bool result = _windowManager.ShowDialog(_viewModel, null, settings) ?? false;
if (result && _action != null)
_action();
return result;
}
}
}
<强>接口强>
namespace Common
{
public interface INavigationService<TVM>
{
INavigationService<TVM> WithParam<TProperty>(Expression<Func<TVM, TProperty>> property, TProperty value);
INavigationService<TVM> DoIfSuccess(System.Action action);
INavigationService<TVM> DoBeforeShow(Action<TVM> action);
void ShowWindow(IDictionary<string, object> settings = null);
bool ShowWindowModal(IDictionary<string, object> settings = null);
}
public interface INavigationService
{
INavigationService<TViewModel> GetWindow<TViewModel>();
}
}
答案 2 :(得分:2)
最新版本的Prism(download here)包含一个名为“Stock Trader”的MVVM应用程序的所谓“参考实现”。我的理由是,如果Prism团队称其为“参考实现”,那么从他们的观点来看这是最“标准”(如果MVVM中的任何内容是标准的),并且是合理的选择。
源包含用于引发模式对话框的基础结构库,这非常好。所以我采用了该库并成功部署了它(我将这样的应用程序上传到Codeplex)。
我需要将代码调整为1将父级图标添加到标题栏,因为库没有提供它;并且[2]将一些有意义的文本添加到标题栏,因为库将其留空并[3]添加一个委托以在对话框关闭时调用。它被抽象到VM可以通过将两个字符串(即Unity注册名称)传递给中介来引发对话的程度。这些更改可在Codeplex上获得。
因此,在所有其他“标准”中,“参考实施”应该作为一种可行的选择进行最低限度的参与。对你的问题更倾斜的答案是,如果你的视图模型被充分隔离并完全通过POCO接口工作,那么在理论中,它应该无关紧要,因为切换到另一个“标准”应该是一个微不足道的练习。
答案 3 :(得分:1)
创建对话服务对我来说效果很好,并且在你的链接中也有建议。
后来我在an MVVM presentation by Gill Cleeren的开发日看到了相同的解决方案。检查工作代码示例的链接(虽然是为Metro写的)
只有让我了解对话服务的一点是,它在某种程度上依赖于UI技术(富客户端)。
简单的请求 - 响应Web前端View可以构建在WPF XAML绑定的相同ViewModel和Model代码之上。直到ViewModel开始通过对话框服务弹出对话框。我不知道如何为Web视图实现对话服务。实现对话框需要向视图推送更多逻辑。
答案 4 :(得分:1)
我只是使用对话服务,请参阅here
在你的viewmodel中你只需要做:
var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);
... do anything with the dialog result...
答案 5 :(得分:0)
使用接口实现对话框的目的是使代码可测试。在这种情况下,“A”被广泛使用,但仍然很难说“标准”。如果您没有对ViewModel进行测试,或者您可以测试ViewModel避免触及对话框,例如使用Extract-Override,则绝对不能按照说明操作。