11

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.

MoonKnight
  • 23,214
  • 40
  • 145
  • 277

6 Answers6

10

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.

Community
  • 1
  • 1
Ibrahim Najjar
  • 19,178
  • 4
  • 69
  • 95
  • 1
    I am no closer to making a decision on an implementation. I want to move in the direction you suggest and have downloaded Prism. However, looking at the source code I cannot see the modules that you are referencing. Can you provide an explicit reference to the classes of Prism I need to inspect? – MoonKnight Jun 27 '13 at 19:23
2

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>();
    }
}
Wojciech Kulik
  • 7,823
  • 6
  • 41
  • 67
2

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.

Gayot Fow
  • 8,710
  • 1
  • 35
  • 48
  • Can you reference you app on CodePlex? Thanks very much for your time it is most appreciated. – MoonKnight Jun 26 '13 at 08:10
  • 1
    https://tyburnphotobrowser.codeplex.com/ The code relevant to my answer is in the Infrastructure\Behaviour directory and also in a Resource Dictionary in the main app directory. Remember to set your target to 4.5 – Gayot Fow Jun 26 '13 at 08:22
  • One quick thing Garry. In WinForms (even for large applications) I rarely need to split solutions into multiple Projects. In your solution you split the components it to a large number of separate projects, why? I am not criticising, but genuinely like to understand best practice here. Thanks again. – MoonKnight Jun 26 '13 at 08:32
  • 1
    If there's too many assemblies to accommodate your style, you can combine them. On Codeplex, however, people usually like to solve a very specific issue (like opening a dialog box :) ) and want to drill down to the relevant assembly without the encumbrance of megalithic refactoring. Also, I'm a big fan of isolation because it makes things easy to test, and easy to 're-use'. I'm quite happy to take the performance hit when VS loads the project in favour of design quality. Please read @jerryjvl answer: http://stackoverflow.com/questions/1192004/specific-down-sides-to-many-small-assemblies – Gayot Fow Jun 26 '13 at 09:31
2

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...
Community
  • 1
  • 1
blindmeis
  • 22,175
  • 7
  • 55
  • 74
1

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.

flup
  • 26,937
  • 7
  • 52
  • 74
0

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.

Bill Zhang
  • 1,909
  • 13
  • 10