Step 1. To start our work let’s create a new WPF application project and save it with name WpfApplication1.
Step 2. We will follow MVVM (Model - View - ViewModel) pattern to develop our simple project. At this step let’s organize project structure and add new folders: Models, ViewModels and Views.
Step 3. Move MainWindow.xaml to Views folder and edit namespaces in xaml and code behind files taking new placement into consideration:
- MainWindow.xaml: x:Class="WpfApplication1.Views.MainWindow";
- MainWindow.xaml.cs: namespace WpfApplication1.Views.
Step 4. Set StartupUri property in App.xaml to "Views/MainWindow.xaml" and run application to check it still works.
Step 5. To implement commands logic we have to use a RelayCommand class, you can download it and save in project root folder. Include RelayCommand.cs in project and change namespace to WpfApplication1.
Step 6. We will execute RelayCommand with parameter further, for this purpose make some changes:
- replace all instances of “Action execute” with “Action<object> execute”;
- replace “this.execute();” with “this.execute(parameter);” in public void Execute(object parameter) method.
or find any other implementation for RelayCommand with parameters.
Step 7. At Steps 7-11 we will create a view model for MainWindow of our project. Add new public class in ViewModels folder and name it MainWindowViewModel.
Step 8. Add using of System.Windows.Input namespace to MainWindowViewModel.cs:
- using System.Windows.Input;
Step 9. Add private field openDialogCommand and corresponding public property:
- private ICommand openDialogCommand = null;
- public ICommand OpenDialogCommand
- {
- get { return this.openDialogCommand; }
- set { this.openDialogCommand = value; }
- }
Step 10. Add private void method OnOpenDialog:
- private void OnOpenDialog(object parameter)
- {
- }
Step 11. Add parameterless constructor for MainWindowViewModel and initialize private field openDialogComand through RelayCommand instance:
- public MainWindowViewModel()
- {
- this.openDialogCommand = new RelayCommand(OnOpenDialog);
- }
Step 12. At steps 12-16 we will associate main window with its view model. Build project. Open App.xaml and add namespace for ViewModels folder:
- xmlns:viewModels="clr-namespace:WpfApplication1.ViewModels"
Step 13. Add resource for MainWindowViewModel to Application.Resources section:
- <viewModels:MainWindowViewModel x:Key="MainWindowViewModel" />
Step 14. Open MainWindow.xaml and declare DataContext property for Window node (along with Title, Height and Width properties):
- DataContext="{StaticResource ResourceKey=MainWindowViewModel}"
Step 15. Add button to Grid node in markup of MainWindow.xaml and specify a Command property through binding to OpenDialogCommand property of data context:
- <Button Content="Button" ... Command="{Binding OpenDialogCommand}" />
Step 16. Put a breakpoint at the open curly brace of OnOpenDialog method in MainWindowViewModel and run the project. Click button and notice the project’s flow stopped at the breakpoint.
PART 2. DIALOG STRUCTURE
Step 17. In this part we will create a base for a modal dialog window. Add a new folder Dialogs to project tree and two subfolders - DialogService and DialogYesNo.
Step 18. All our dialogs must return a result of choice made by user. Add a new item DialogResultEnum.cs to DialogService folder, replace class with enum and define structure with possible dialog result values, for example:
- public enum DialogResult
- {
- Undefined,
- Yes,
- No
- }
Step 19. Add a new Window (WPF) to DialogService folder and name it DialogWindow.
Step 20. Add a property WindowStartupLocation to Window node and replace Grid section in DialogWindow markup with ContentPresenter node:
- <Window x:Class="WpfApplication1.Dialogs.DialogService.DialogWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="DialogWindow" Height="300" Width="300"
- WindowStartupLocation="CenterScreen">
- <ContentPresenter x:Name="ContentPresenter" Content="{Binding}"></ContentPresenter>
- </Window>
Step 21. Add a new public static class DialogService.cs to DialogService folder and define public static method OpenDialog which returns DialogResult:
- public static DialogResult OpenDialog()
- {
- DialogWindow win = new DialogWindow();
- win.ShowDialog();
- return DialogResult.Undefined;
- }
Step 22. Get back to MainWindowViewModel, and modify OnOpenDialog method:
- private void OnOpenDialog(object parameter)
- {
- Dialogs.DialogService.DialogResult result =
- Dialogs.DialogService.DialogService.OpenDialog();
- }
Step 23. Run project, put a breakpoint at closing curly brace in OnOpenDialog method and click button in main window. Dialog window should appear and result variable should have a DialogResult.Undefined value after closing the dialog.
PART 3. DIALOG VIEW
Step 24. In this part we will add a view for our modal dialog and define some logic. Add new public abstract class DialogViewModelBase to DialogService folder:
- public abstract class DialogViewModelBase
- {
- }
Step 25. Add new user control (WPF) to DialogYesNo folder and name it DialogYesNoView, place two buttons as a content of the control:
- <UserControl x:Class="WpfApplication1.Dialogs.DialogYesNo.DialogYesNoView"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- mc:Ignorable="d"
- d:DesignHeight="100" d:DesignWidth="300">
- <Grid Margin="4">
- <Button Content="Yes" HorizontalAlignment="Left" Margin="135,70,0,0" VerticalAlignment="Top" Width="75"/>
- <Button Content="No" HorizontalAlignment="Left" Margin="215,70,0,0" VerticalAlignment="Top" Width="75"/>
- </Grid>
- </UserControl>
Step 26. Add a new class to DialogYesNo folder and name it DialogYesNoViewModel, make DialogYesNoViewModel derived from DialogViewModelBase.
Step 27. Add two commands to process Yes and No buttons click (similarly for button at main window, see Steps 8-9):
- class DialogYesNoViewModel : DialogViewModelBase
- {
- private ICommand yesCommand = null;
- public ICommand YesCommand
- {
- get { return yesCommand; }
- set { yesCommand = value; }
- }
- private ICommand noCommand = null;
- public ICommand NoCommand
- {
- get { return noCommand; }
- set { noCommand = value; }
- }
- public DialogYesNoViewModel()
- {
- this.yesCommand = new RelayCommand(OnYesClicked);
- this.noCommand = new RelayCommand(OnNoClicked);
- }
- private void OnYesClicked(object parameter)
- {
- }
- private void OnNoClicked(object parameter)
- {
- }
- }
Step 28. Modify DialogYesNoView and add Command properties to Yes and No buttons. Pay attention to CommandParameter property - we will pass a reference to the hosting window as a parameter to commands:
- <Button Content="Yes" HorizontalAlignment="Left" Margin="135,70,0,0" VerticalAlignment="Top" Width="75"
- Command="{Binding YesCommand}"
- CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
- <Button Content="No" HorizontalAlignment="Left" Margin="215,70,0,0" VerticalAlignment="Top" Width="75"
- Command="{Binding NoCommand}"
- CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
Step 29. Get back to App.xaml and add namespace for DialogYesNo folder:
- xmlns:dialogYesNo="clr-namespace:WpfApplication1.Dialogs.DialogYesNo"
Step 30. Append an Application.Resources section with a resource for data template to associate DialogYesNoViewModel with DialogYesNoView:
- <DataTemplate DataType="{x:Type dialogYesNo:DialogYesNoViewModel}">
- <dialogYesNo:DialogYesNoView></dialogYesNo:DialogYesNoView>
- </DataTemplate>
Step 31. Get back to DialogWindow.xaml and add SizeToContent property to Window node along with WindowStartupLocation property:
- SizeToContent="WidthAndHeight"
Step 32. Modify signature of OpenDialog static method in DialogService, let the method accept a parameter of type DialogViewModelBase and define win variable’s DataContext property:
- public static DialogResult OpenDialog(DialogViewModelBase vm)
- {
- DialogWindow win = new DialogWindow();
- win.DataContext = vm;
- win.ShowDialog();
- return DialogResult.Undefined;
- }
Step 33. Get back to MainWindowViewModel to modify call of DialogService.OpenDialog(). Create instance of DialogViewModelBase instantiated with DialogYesNoViewModel and pass it as an argument to DialogService.OpenDialog():
- private void OnOpenDialog(object parameter)
- {
- Dialogs.DialogService.DialogViewModelBase vm =
- new Dialogs.DialogYesNo.DialogYesNoViewModel();
- Dialogs.DialogService.DialogResult result =
- Dialogs.DialogService.DialogService.OpenDialog(vm);
- }
Now we have a modal YesNo dialog with empty commands to process buttons click, and the dialog still returns DialogResult.Undefined value after closing.
PART 4. DIALOG RESULT
Step 34. Get back to DialogViewModelBase, add public property UserDialogResult of type DialogResult:
Etienne CharlandPosted May 30, 2022, 4:45 AM
This is many years late, but you might want to consider using a framework like HanumanInstitute.MvvmDialogs (for WPF and Avalonia) to make the process a lot easier https://github.com/mysteryx93/HanumanInstitute.MvvmDialogs
David BentleyPosted Dec 7, 2017, 11:39 AM
This was very good to help, but I found several places for improvement. One big one is binding the window title. It was very easy to add and something you should update in this article. What I did was add another string overload to DialogViewModelBase and then changed the window title binding to that string. Pretty easy. It is also better to actually pass an object or helper class into the dialog. This opens up more opportunity to pass information to your dialog.
NehaPosted Jan 17, 2017, 4:57 AM
Nice.................................
kalu singh raoPosted Jul 12, 2016, 1:48 AM
Nice...
Vignesh ManiPosted Apr 29, 2016, 8:41 AM
Nice
Vivek KumarPosted Apr 28, 2016, 2:39 PM
Good one
RakeshPosted Apr 28, 2016, 1:55 PM
Good share
Rahul Kumar SaxenaPosted Apr 28, 2016, 1:27 PM
Good Show
Kishor Bikram OliPosted Apr 28, 2016, 12:39 PM
great work!
Mohammed IbrahimPosted Apr 28, 2016, 12:08 PM
nice
Debasis SahaPosted Apr 28, 2016, 10:45 AM
Good One..
Thiruppathi RPosted Apr 28, 2016, 8:51 AM
Good job