[CaliburnMicro] Embedded MessageBox

In this article, I'll show you how to use Caliburn Micro to create embedded message boxes. I will use the default implementation you can obtain in CM's big brother source code, and tweak it a little to have a better look.


I've decided to keep the static Show class from Caliburn. So, when you wish to display a message box, you just have to call

The Caliburn's version of the MessageBoxResult returned from Show.MessageBox calls ShowMessageBox from the IWindowManager interface, which basically creates a new window "on-the-fly" and sets the content of this window with an instance of the QuestionDialogViewModel class.

I'm going to keep the principle, but instead of displaying the message box in a new window, I will set a property of type IQuestionDialog on my shell view-model. The view of the shell will have a ContentControl, which will have a dependency property of type View.Model bound to the property. That ContentControl will be collapsed by default, and using a converter, we will display it when the property of the view-model is not null. Putting the ContentControl above all the other controls of the shell view-model will then just be a matter of some XAML coding.

Let's begin to write the IQuestionDialog interface:

From the original implementation, I now use only one question, and I added an OnClose event.

The QuestionDialogViewModel is implemented as:

The code is much more simpler than in the original version, because I removed the multi-questions, and because the NotifyOfPropertyChanged calls have disappeared, thanks to PostSharp. You have to notice that I raise the OnClose event when the SelectAnswer method is called.

Here is the XAML code of the view:

 

This is a basic UserControl which will be resized automatically, according to the length of the question. It will display the Caption on top, the Question.Text in the middle, and the buttons (bound to the Question.PossibleAnswers) are in the bottom, aligned on the right. There are also some cosmetics improvements, like rounded borders, and a drop shadow. Also, you will see that clicking on a button will call the SelectAnswer method of QuestionDialogViewModel.

Now is the time to modify the shell view, to add the ContentControl:

As you can see, I add a new Grid, with a semi-transparent color, which will cover the entire view. I define the visibility of this grid to Collapsed by default. The IsNullConverter will trigger the modification of the visibility, making it Visible if the QuestionDialogViewModel property is not-null. In this grid, I've put the ContentControl, which, like I already said, will display the content of the QuestionDialogViewModel property.

Speaking about the IsNullConverter:

The last step is to write the MessageBoxResult class:

In the Execute method, after CM has injected the dependencies of the result (and then got the instance of IShellViewModel, and a new instance of IQuestionDialog), I first set the property of the shell view-model, but I don't raise the Completed event now. Instead, it is raised when the user has clicked on one of the buttons of the QuestionDialogViewModel. If you remember, clicking on a button will call the SelectAnswer method of QuestionDialogViewModel, which will raise the OnClose event. Here I subscribe to this event, so I can unset the QuestionDialogViewModel property of IShellViewModel, to hide the message box, and finally to complete the result, in order for the caller to continue the execution of the co-routine.

As a last note, I remind you not to forgive to configure your dependency injection framework to resolve IShellViewModel in a singleton scope. That will help you to save some time 😉

I hope you enjoyed this article.

Happy coding!