(Note this article refers to a pre-release version, which can be found on nuget provided pre-release versions are included in your search.)
Message boxes. Ever a source of frustration in WPF. MahApps has some nice dialog boxes to which I recently helped out with an MVVM API, but Material Design In XAML Toolkit can run with or without MahApps so I wanted a custom implementation which would meet these goals:
- Look similar to the dialogs we see on Android phones
- Have an API which is useable from XAML, code-behind, and MVVM
- Provide full flexibility on the content of the dialog.
All software is evolution and after a reasonable attempt of doing something similar for a client – which ended up with a bit of a code-smell around callbacks from the API – I’ve come up some composable pieces which I hope are flexible, easy to use, and – most importantly – provide an attractive GUI 🙂
The cornerstone is the DialogHost control. It’s a content control, meaning the underlying content over which the popup dialog will be displayed can be targeted; to a specific area of your app, or the entire Window content.
<md:DialogHost> <md:DialogHost.DialogContent> <dialogContent /> </md:DialogHost.DialogContent> <mainContent /> </md:DialogHost>
When the dialog is open, the underlying content will be dimmed and disabled.
DialogHost.DialogContent (associated with DialogHost.DialogContentTemplate) is your typical XAML content object property for setting the content of your dialog. You can infer from this that you can use MVVM to bind content, but there are multiple ways of populating the content, showing the dialog, closing the dialog, and processing responses, so here’s a list of all the strategies for using the dialog (after the gif):
Open Dialog Strategies
DialogHost.OpenDialogCommand
<Button Command="{x:Static md:DialogHost.OpenDialogCommand}" />
RoutedCommand typically used from a button where optional content can be provided via the CommandParameter.
DialogHost.IsOpen
<md:DialogHost IsOpen="True" />
Dependency property, to be triggered from XAML, set from code-behind or via a binding. Content must be set in DialogHost.DialogContent.
DialogHost.Show
DialogHost.Show(viewOrModel);
Async/await based static API which can be used purely in code (for example from in a view model). Content can be passed directly to the dialog.
Close Dialog Strategies
DialogHost.CloseDialogCommand
<Button Command="{x:Static md:DialogHost.CloseDialogCommand}" />
RoutedCommand, typically used on buttons inside the dialog, where the command parameter will be passed along to the dialog response.
DialogHost.IsOpen
<md:DialogHost IsOpen="False" />
Dependency property, to be triggered from XAML, set from code-behind or via a binding.
HANDLE CLOSE STRATEGIES
The DialogClosingEventHandler delegate is key. It provides the parameter provided to DialogHost.CloseDialogCommand, and allows the pending close to be cancelled.
The following mechanisms allow handling of this event, via code-behind, MVVM practices, or just from the code API:
DialogHost.DialogClosing
<md:DialogHost DialogClosing="DialogHost_OnDialogClosing" />
Bubbling RoutedEvent, which could be used in code-behind.
DialogHost.DialogClosingAttached
<Button Command="{x:Static wpf:DialogHost.OpenDialogCommand}" md:DialogHost.DialogClosingAttached="DialogHost_OnDialogClosing" />
Attached property, which accepts a DialogClosingEventHandler which makes it easy to subscribe to the closing event in a more localized area of XAML.
DialogClosing.DialogClosingCallback
<md:DialogHost DialogClosingCallback="{Binding DialogClosingHandler}" />
Standard dependency property which enables the a DialogClosingEventHandler implementation to be bound in, typically from a view model.
DialogHost.Show
var result = await DialogHost.Show(viewOrModel, ClosingEventHandler);
The async response from this method returns the parameter provided when DialogHost.CloseDialogCommand was executed. As part of the Show() signature a DialogClosingEventHandler delegate can be provided to intercept the on-closing event, just prior to the close.
More Examples
More complete usage examples can be found in MainDemo.Wpf which is part of the Toolkit solution, primarily in MainDemo.Wpf/Dialogs.xaml.
Can you help me please how can I create message dialog box for as popup for alert. I am trying from last few days but the problem is that when I try to call dialog box without MVVm from C# the button becomes disabled.
Can you help me please how to create dialog box without MVVM like warning popup message box.
Thanks in advance 🙂
Hi…if your button is disabled I suspect it is outside of the DialogHost. Either put a DialogHost at the root of all your XAML (so that the button is inside it somewhere), or specify the CommandTarget on your button to point to your DialogHost.
Nop button is inside. Even I downloaad your demo app. Ony sample 1 working other buttons are disabled. If you just writte a simple code without MVVM like messagebox then it would be great help for me. and I just call it from external button from code behind not from xaml. I am not a good programmer. 😦 Thanks!
Hey, you might find it easier to talk in the Gitter chat room: https://gitter.im/ButchersBoy/MaterialDesignInXamlToolkit
Hi, I have a conceptual question about how you give feedback to user if you’re already in a dialog box. On my main window I call a DialogHost.Show and pass a user control as parameter, where the user can input some data. But I need to give the user some information if an error occurs. I’m doing this using DialogHost,Show again but then I get this error: DialogHost is already open. Do you have any advice on this?
Yes, check out the “Extended” button on the dialogs page in the demo. This shows you how to update existing content.
Great article.
Hi James, how can I bind DialogClosing to a RelayCommand that resides inside my ViewModel (MVVM style)?
There’s various methods of handling close: https://github.com/ButchersBoy/MaterialDesignInXamlToolkit/wiki/Dialogs#handle-close-strategies
This a covered in the 4 or 5 examples actually in the demo. Personally, in a MVVM use-case, I like to use the static DialogHost.Show method. One overload of the method allows provision of an event handler to listen to closing events.
HI James! Is there any way to unit testing a method what use DialogHost.Show?
I suggest you wrap the .show method in your own class/interface, and object that into your code.
Hi! Recently I want to do a dialog box with a GIF loading, but it’s closed when you perform a function, how can I do this? Any idea? Or other ways? The dialog box opens when a button is pressed and hopefully close automatically. Thank you.
If I understand what your are saying, you want to use the dialog .Session to closer the dialog when you are ready. You can get the Session from the opening event arguments.
I solved my problem! Thank’s! Very good your work! Congratulations!
Hi James, is there is a way to turn off backgroud overlay, or made it transparent?
Not without re-styling, however in the next version the Opacity is lowered.
HI James,
Is there are a way to resize dialog box at run time by End user. Like we do resize a window by dragging from corner. thanks
Not currently, but please feel free to raise this as a feature request on the GitHub project issues page.
Hi James,
Thanks for this great library.
Is there a way to apply the current theme to the Dialog Boxes?
When I use dark theme my dialogs have always light theme!
Thanks.
That is by design… But yes you can, but you have to apply the Dark resource locally…I might make this optional in future though… Stop by the Gitter chatroom (link on project page) if you want to chat further
Thanks for this very fast answer.
How can I open a loading dialog from code C#. I want to load some data from the data bank, I created a new thread and I would like to use the Material Design dialog. I am currently using Busy indicator from Xceed, but it does no match the Material Design.
Use DialogHost.Show, illustrated here: https://github.com/ButchersBoy/MaterialDesignInXamlToolkit/wiki/Dialogs#dialoghostshow
Then, inside the callback you can spin up your new thread. You can pass a progress bar with the circular style (easiest inside a userControl) into the dialog.
The positive and negative buttons are in the wrong order. It should be Negative – Positive
https://material.io/guidelines/components/dialogs.html#dialogs-specs
(and postivie – negative when in RTL)
how to close on black/outside area onclick ???