Introduction
The purpose of this article is to demonstrate an idea on how to manage Dialog boxes in WPF application. As most of the developers know, using Dialog boxes is always needed and unavoidable in desktop applications, and you often see dialog boxes used for configuration settings, communicate information or error messages to user and so on. Improper use and display of dialog boxes not only clutter the application client area and Windows Taskbar, some of them might be sent behind the application's main window due to overlapping dialog boxes and the z-Index order.
Background
This issue is not new and has been known since the birth of Windows operating system as Windows itself also faces the same issue of managing the open application windows in the Windows Explorer. A decent solution from Windows Aero is that it tries to manage this issue by consolidating the instances of the same application as one taskbar icon, so that it can accommodate more application icons in the Taskbar. You can read more information about Windows Aero from the WIKIPEDIA.
This article showcases that WPF application uses a singleton modeless window as a container for all the dialog boxes, which means user sees one and only one dialog window no matter how many dialog boxes are displayed on the screen. However, user can navigate among the dialog boxes or locate a specific dialog box through the navigation controls in the application taskbar. The navigation controls are:
DialogTaskbar
Each icon in the DialogTaskbar
represents an open dialog box. User can navigate among the dialog boxes through the Backward (<) and Forward (>) navigation buttons or using the shortcut keys (Page up and Page down, Left key and Right key).
DialogThumbnail
A number indicator overlay icon to indicate the number of open dialog boxes. User can navigate among the dialog boxes through a popup list when hovering over the taskbar icon.
Understand the Code
The library provided in this article is made up of the following fundamental building blocks:
DialogService
DialogServiceWindow
DialogServiceViewModel
ViewModelBase
DialogService
It is a concrete implementation of IDialogService
interface. Application uses it to display the dialog boxes to user. It has the following methods:
ShowDialog
- Show the dialog on the screen immediately.
AddDialog
- Add a dialog to the collection but do not replace the opened dialog.
RemoveDialog
- Remove the dialog from the screen. This is useful for asynchronous work, where a progress dialog is shown when starting a background job and removes it from the screen upon completion.
ContainsDialog
- Determine whether a dialog is in the collection.
DialogServiceViewModel
This is the model of DialogService
. It uses an ObservableCollection
to hold a collection of DialogItem
(dialog boxes). Besides, it is also the data binding model for the DialogServiceWindow
, DialogTaskbar
and DialogThumbnail
navigation controls. It has the following properties and methods:
Items
- An ObservableCollection
of DialogItem
.
SelectedItem
- The current selected DialogItem
. The selected dialog box is displayed on the screen.
MoveNext
- A DelegateCommand
which selects the next DialogItem
in the collection when invoked.
MovePrevious
- A DelegateCommand
which selects the previous DialogItem
in the collection when invoked.
MoveToIfEmpty
- Shows the specified dialog box if no other dialog box is displayed.
MoveTo
- Shows the specified dialog box.
RemoveItem
- Removes a specified dialog box from the collection.
DialogServiceWindow
This is a non-modal Window which is the container for all the displayed dialog boxes. Its non-client area does not have System Menu, Minimized, Maximized, Restored and Close buttons, but only the caption title.
ViewModelBase
The view model of dialog box must derive from ViewModelBase
class. It provides a few helper functions and a RequestClose
event which will be used by DialogService
to close the dialog box when its OnRequestClose
method is invoked. All the dialog boxes must invoke the OnRequestClose
method to close itself when it has fulfilled its intended purpose.
Using the Code
It takes only 3 steps to display a custom dialog using the library provided in this article.
Step 1. Design a Dialogbox
- Design a dialog box in
UserControl
.
- Derive the {xxx}ViewModel of
Dialogbox
from ViewModelBase
.
- Bind the {xxx}ViewModel to the
Dialogbox
's DataContext
.
Note: Remember to invoke the OnRequestClose
method to close the dialog when it has fulfilled its intended purpose.
private ICommand _closeCommand;
public ICommand CloseCommand
{
get { return _closeCommand ?? (_closeCommand = new DelegateCommand(OnRequestClose)); }
}
Step 2. Setup the Runtime Environment
In the code listing below, I use Ninject dependency injection container to setup the runtime environment.
[STAThread]
public static void Main(string[] args)
{
var app = new App();
var container = app.Container; MainWindow mainWindow = new MainWindow();
mainWindow.Show();
container.Bind<IDialogService>().To<DefaultDialogService>().InSingletonScope();
var dialogService = container.Get<IDialogService>();
container.Bind<IDialogWindow>().ToMethod(context =>
{
return new DialogServiceWindow(dialogService.Model)
{
Owner = mainWindow,
ShowInTaskbar = false
};
}).InSingletonScope();
dialogService.DialogWindow = container.Get<IDialogWindow>();
mainWindow.DialogTaskbar.DataContext = dialogService.Model;
mainWindow.DialogThumbnail.DataContext =
new DialogThumbnailViewModel(dialogService.Model);
mainWindow.DataContext = new MainWindowViewModel(dialogService);
app.Run(mainWindow);
}
Step 3. Show the Dialogbox
The last step is to invoke the ShowDialog
method to display the dialog box on the screen.
public MainWindowViewModel(IDialogService dialogService)
{
dialogService.ShowDialog(
new DialogItem(
"About Jellyfish",
"The photo you're seeing is a Jellyfish.
\nThis photo is taken from the Windows 7 Pictures Library.",
new AboutDialog(new AboutDialogVM())));
}
As a library, it has a built-in dialog, which can be used to show a simple Information, Warning or Error message to the user.
private ICommand _openInfoDialogCommand;
public ICommand OpenInfoDialogCommand
{
get
{
return (_openInfoDialogCommand ?? (_openInfoDialogCommand = new DelegateCommand(
() => _dialogService.ShowMessage
("Information Dialog", "This is a Information Dialog.", MessageType.Info))));
}
}
Information Dialogbox
Warning Dialogbox
Error Dialogbox
Points of Interest
Last but not least, I've included a sample, available from the link at the top of this article, which demonstrates what I've described in this article.
History
- 9th December, 2011: Initial version