Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Standard Approach of Launching Dialogs/Child Windows from a WPF Application using MVVM

Tags:

c#

mvvm

dialog

wpf

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.

like image 582
MoonKnight Avatar asked Jun 25 '13 22:06

MoonKnight


2 Answers

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.

like image 136
Ibrahim Najjar Avatar answered Oct 14 '22 11:10

Ibrahim Najjar


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>();
    }
}
like image 41
Wojciech Kulik Avatar answered Oct 14 '22 10:10

Wojciech Kulik