Custom MessageDialog with MVVM

By default the WinRT MessageDialog only allows for text and buttons (think in the meaning of Confirm - Cancel). If you’re in need of more advanced dialogs, e.g. providing some data entry to validate a user’s login credentials, you’ll have to take care of it yourself. It’s rather easy to create a Flyout containing custom controls, but if you want the look and feel of the MessageDialog you’re in for a much tougher job. Luckily Tim Heuer provided us the CustomDialog control in his Callisto library.

In my scenario I’m asking the user for his name and age. Depending on whether he chooses to save or cancel the entered values, I update the model behind my main page or leave it as is. For this I simply use 2 different object instantiations of the same Person model, one for the view and one for the dialog. Note that I make use of the BindableBase class provided with the default templates and also part of Prism for Universal apps. This base class already implements INotifyPropertyChanged and greatly simplifies my properties.

internal class Person : BindableBase
{
    private string _firstname;
    public string Firstname
    {
        get { return _firstname; }
        set { SetProperty(ref _firstname, value); }
    }

    private string _lastname;
    public string Lastname
    {
        get { return _lastname; }
        set { SetProperty(ref _lastname, value); }
    }

    private string _age;
    public string Age
    {
        get { return _age; }
        set { SetProperty(ref _age, value); }
    }
}

I usually use MVVM to create my apps and like to keep the code behind of a view as clean as possible. Next to that I try to keep any view related types out of my viewmodel. There’s no use in decoupling your view if you create a UI control in your viewmodel. This means I need a clean way to open and close the CustomDialog from within my viewmodel and be able to respond to both save and cancel actions.

To manage the visibility of the dialog, I can simply bind a boolean value to the IsOpen dependency property. For feedback on the user’s decision, I’m using command bindings on the buttons and finally the data itself is retrieved with TwoWay-bindings. For this demo I have placed the TextBox controls in a separate user control, but this is optional.

Custom Dialog MVVM

I enabled showing the backbutton on the modal dialog. By default this closes the dialog, so you can choose between this back button and a cancel button (for demo purposes I picked both). Note that it is very important that the IsOpen binding is a TwoWay binding. If not, you won’t be able to re-open the dialog. I happened to be in this scenario and found others have experienced the same problem. The explanation is simple and can be found in the source code of Callisto.

if (_backButton != null)
{
    _backButton.Click += (bbs, bba) =>
        {
            if (BackButtonClicked != null)
            {
                BackButtonClicked(bbs, bba);
            }
            else
            {
                IsOpen = false;
            }
        };
}

source: Callisto

When the back button is clicked, the IsOpen property is updated in the control’s code. If your binding isn’t TwoWay, the viewmodel doesn’t get updated and you lose your binding.

You can find a sample solution on Github.

Licensed under CC BY-NC-SA 4.0; code samples licensed under MIT.
comments powered by Disqus
Built with Hugo - Based on Theme Stack designed by Jimmy