Handling Dialogs in WPF with MVVM

2019-01-01 04:44发布

In the MVVM pattern for WPF, handling dialogs is one of the more complex operations. As your view model does not know anything about the view, dialog communication can be interesting. I can expose an ICommand that when the view invokes it, a dialog can appear.

Does anyone know of a good way to handle results from dialogs? I am speaking about windows dialogs such as MessageBox.

One of the ways we did this was have an event on the viewmodel that the view would subscribe to when a dialog was required.

public event EventHandler<MyDeleteArgs> RequiresDeleteDialog;

This is OK, but it means that the view requires code which is something I would like to stay away from.

23条回答
何处买醉
2楼-- · 2019-01-01 04:50

I rolled my own window loader described in an answer to this question:

Managing multiple WPF views in an application

查看更多
与君花间醉酒
3楼-- · 2019-01-01 04:52

I think that the handling of a dialog should be the responsibility of the view, and the view needs to have code to support that.

If you change the ViewModel - View interaction to handle dialogs then the ViewModel is dependant on that implementation. The simplest way to deal with this problem is to make the View responsible for performing the task. If that means showing a dialog then fine, but could also be a status message in the status bar etc.

My point is that the whole point of the MVVM pattern is to separate business logic from the GUI, so you shouldn't be mixing GUI logic (to display a dialog) in the business layer (the ViewModel).

查看更多
皆成旧梦
4楼-- · 2019-01-01 04:54

EDIT: yes I agree this is not a correct MVVM approach and I am now using something similar to what is suggested by blindmeis.

One of the way you could to this is

In your Main View Model (where you open the modal):

void OpenModal()
{
    ModalWindowViewModel mwvm = new ModalWindowViewModel();
    Window mw = new Window();
    mw.content = mwvm;
    mw.ShowDialog()
    if(mw.DialogResult == true)
    { 
        // Your Code, you can access property in mwvm if you need.
    }
}

And in your Modal Window View/ViewModel:

XAML:

<Button Name="okButton" Command="{Binding OkCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">OK</Button>
<Button Margin="2" VerticalAlignment="Center" Name="cancelButton" IsCancel="True">Cancel</Button>

ViewModel:

public ICommand OkCommand
{
    get
    {
        if (_okCommand == null)
        {
            _okCommand = new ActionCommand<Window>(DoOk, CanDoOk);
        }
        return _okCommand ;
    }
}

void DoOk(Window win)
{
    <!--Your Code-->
    win.DialogResult = true;
    win.Close();
}

bool CanDoOk(Window win) { return true; }

or similar to what is posted here WPF MVVM: How to close a window

查看更多
柔情千种
5楼-- · 2019-01-01 04:55

I suggest forgoing the 1990's modal dialogs and instead implementing a control as an overlay (canvas+absolute positioning) with visibility tied to a boolean back in the VM. Closer to an ajax type control.

This is very useful:

<BooleanToVisibilityConverter x:Key="booltoVis" />

as in:

<my:ErrorControl Visibility="{Binding Path=ThereWasAnError, Mode=TwoWay, Converter={StaticResource booltoVis}, UpdateSourceTrigger=PropertyChanged}"/>

Here's how I have one implemented as a user control. Clicking on the 'x' closes the control in a line of code in the usercontrol's code behind. (Since I have my Views in an .exe and ViewModels in a dll, I don't feel bad about code that manipulates UI.)

Wpf dialog

查看更多
与风俱净
6楼-- · 2019-01-01 04:56

You should use a mediator for this. Mediator is a common design pattern also known as Messenger in some of its implementations. It's a paradigm of type Register/Notify and enables your ViewModel and Views to communicate through a low-coupled messaging mecanism.

You should check out the google WPF Disciples group, and just search for Mediator. You will be much happy with the answers...

You can however start with this:

http://joshsmithonwpf.wordpress.com/2009/04/06/a-mediator-prototype-for-wpf-apps/

Enjoy !

Edit: you can see the answer to this problem with the MVVM Light Toolkit here:

http://mvvmlight.codeplex.com/Thread/View.aspx?ThreadId=209338

查看更多
皆成旧梦
7楼-- · 2019-01-01 04:57

I know it's an old question, but when I did this search, I find a lot of related question, but I did not find a really clear response. So I make my own implementation of a dialogbox/messagebox/popin, and I share it!
I think it is "MVVM proof", and I try to make it simple and proper, but I am new to WPF, so feel free to comment, or even make pull request.

https://github.com/Plasma-Paris/Plasma.WpfUtils

You can use it like this:

public RelayCommand YesNoMessageBoxCommand { get; private set; }
async void YesNoMessageBox()
{
    var result = await _Service.ShowMessage("This is the content of the message box", "This is the title", System.Windows.MessageBoxButton.YesNo);
    if (result == System.Windows.MessageBoxResult.Yes)
        // [...]
}

Or like this if you want more sophisticated popin :

var result = await _Service.ShowCustomMessageBox(new MyMessageBoxViewModel { /* What you want */ });

And it is showing things like this :

2

查看更多
登录 后发表回答