Standard Approach of Launching Dialogs/Child Windo

2019-02-09 18:47发布

All, I would like to know the recognised best approach/industry standard of launching [child] dialogs/windows from an WPF using the MVVM pattern. I have come across the following articles:

A. CodeProject - Showing Dialogs When Using the MVVM Pattern

This approach seems good but excessive to me. The is some degree of code replication and I am not convinced this is the right way to go.

B. WPF MVVM and Showing Dialogs

This briefly runs through three options with various links which are all fairly/very poor at explaining the methodology or are of-topic.

Can someone please provide an explanation of the industry standard method/approach of launching dialogs from a WPF application using MVVM and preferably some links to further reading material? If you can provide an example yourself I would of course be most appreciative!

Thanks for your time.

标签: c# wpf mvvm dialog
6条回答
干净又极端
2楼-- · 2019-02-09 19:11

Creating a dialog service has worked out well for me, and is also suggested in both your links.

Later I saw the same solution at the dev days in an MVVM presentation by Gill Cleeren. Check the link for working code samples (though written for Metro)

Only thing that nags me a bit about the dialog service is that it is in some way UI technology (rich client) dependent.

A simple request-response web frontend View can be built on top of the same ViewModel and Model code that the WPF XAML binds to. Until the ViewModel starts popping up dialogs through the dialog service. I would not know how to implement the dialog service for a web view. Implementing dialogs there would require pushing a bit more logic to the view.

查看更多
欢心
3楼-- · 2019-02-09 19:15

The most recent release of Prism (download here) contains a so-called "Reference Implementation" of an MVVM application called "Stock Trader". My rationale was that if the Prism team is calling it a "Reference Implementation", that's the most "standard" from their point of view (if anything in MVVM is standard), and the logical choice to press on with.

The source contains an infrastructure library for raising modal dialogs, and it's pretty good. So I adopted that library and have deployed it successfully (I uploaded such an app to Codeplex).

I needed to tweak the code to 1 add the parent's icon to the title bar because the library didn't provide for it; and [2] add some meaningful text to the title bar because the library left it blank and [3] add a delegate to invoke when the dialog closes. It's abstracted to the extent that a VM can raise a dialog by passing two strings (i.e., the Unity Registration Names) to a mediator. Those changes are available on Codeplex.

So among all the other 'standards' the "Reference Implementation" should minimally participate as a viable choice. The more oblique answer to your question is that if your View Models are sufficiently isolated and work entirely through POCO interfaces, then in THEORY, it shouldn't matter because switching to another 'standard' should be a trivial exercise.

查看更多
欢心
4楼-- · 2019-02-09 19:19

Purpose of using interface to implement dialogs is to make code testable. In this case, "A" is widely used, but it is still hard to say "Standard". If you do not have test on your ViewModel or you can test your ViewModel avoid touching dialogs, such as using Extract-Override, you can definitely do not follow the instruction.

查看更多
对你真心纯属浪费
5楼-- · 2019-02-09 19:20

Recently, I've implemented my own Navigation Service for WPF, which uses Caliburn.Micro's WindowManager (but you could replace it by something else).

Example (how to use):

_navigationService.GetWindow<ClientDetailsViewModel>()
            .WithParam(vm => vm.IsEditing, true)
            .WithParam(vm => vm.Client, SelectedClient)
            .DoIfSuccess(() => RefreshSelectedClient())
            .ShowWindowModal();

Implementation:

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

Interfaces:

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>();
    }
}
查看更多
放我归山
6楼-- · 2019-02-09 19:28

First of all, i don't know of any "industry-standard" way for showing dialogs using MVVM because there is no such thing.
Secondly, Welcome to MVVM, you have just touched on of the areas that MVVM don't have a standard for.
To tell you the truth, MVVM has many pain points and this is the reason why there are tons of MVVM frameworks out there, just to mention a few MVVM Light, PRISM, Caliburn.Micro, Cinch, Catel, WAF, Baboon, shell i stop or you want more.
Now to answer your question and after dealing with most of those frameworks, i noticed one commonality, they all use a DI/IoC container and then provide you with an interface, something like IDialogManager and an implementation of their own, and then they ask you to accept this interface in your view model and use it to show dialogs. So to sum this up, i would use dependency injection, have an interface for showing dialogs, and then provide and implementation of that, and register it with the di container and then consume it from my view model or views.
Edit: So you have picked PRISM (which in my opinion) is hardest between them all in showing dialogs. Now that's aside, there is the hard way which is by using Interaction Requests (check the middle of the article), or you can use this Answer as a quicker way.

查看更多
来,给爷笑一个
7楼-- · 2019-02-09 19:35

i simply use a dialogservice, see here

within your viewmodel you just have to do:

var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);

... do anything with the dialog result...
查看更多
登录 后发表回答