使用MVVM从WPF应用程序启动对话框/子窗口的标准方法

时间:2013-06-25 22:58:25

标签: c# wpf mvvm dialog

所有,我想知道使用MVVM模式从WPF启动[子]对话框/窗口的公认最佳方法/行业标准。我遇到过以下文章:

一个。 CodeProject - Showing Dialogs When Using the MVVM Pattern

这种做法看起来不错,但对我来说太过分了。这是一定程度的代码复制,我不相信这是正确的方法。

B中。 WPF MVVM and Showing Dialogs

这简要介绍了三个选项,其中包含各种链接,这些链接在解释方法或主题方面都相当/非常差。

有人可以提供使用MVVM从WPF应用程序启动对话框的行业标准方法/方法的解释,最好是一些链接到进一步的阅读材料吗?如果你能自己提供一个例子我当然会非常感激!

感谢您的时间。

6 个答案:

答案 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,则绝对不能按照说明操作。