Example T387258
Visible to All Users

How to Use the WPF WizardService

This example demonstrates how to use the WizardService and specify the visibility and availability of wizard buttons.

image

Implementation Details

The WizardService generates WizardPages based on the template defined by the PageGeneratorTemplate property. This template allows you to implement navigation between pages at the ViewModel level. In this example, the WizardPage's Allow_ and Show_ properties are bound to the page's ViewModel properties. Use these properties to hide and disable specific navigation buttons.

XAML
<dxco:WizardService> <dxco:WizardService.PageGeneratorTemplate> <DataTemplate> <dxco:WizardPage ShowNext="{Binding ShowNext}" ShowBack="{Binding ShowBack}" ShowCancel="{Binding ShowCancel}" ShowFinish="{Binding ShowFinish}" AllowNext="{Binding AllowNext}" AllowBack="{Binding AllowBack}" AllowCancel="{Binding AllowCancel}" AllowFinish="{Binding AllowFinish}" /> </DataTemplate> </dxco:WizardService.PageGeneratorTemplate> </dxco:WizardService>

You can specify Show_ and Allow_ properties in both WizardPage and Wizard. The Wizard's properties have a higher priority than corresponding WizardPage's properties.

ViewModels in this project implement ISupportWizard_Command interfaces that expose the Can_ property and the On_ method. Use the Can_ property to enable/disable the corresponding navigation button. When a user clicks the button, the Wizard executes the On_ method, and the WizardService.Navigate method switches the Wizard to the specified page. The ISupportWizard_Command's properties have a higher priority than corresponding WizardPage's properties.

C#
public class WelcomePageViewModel : WizardViewModelBase, ISupportWizardNextCommand { protected WelcomePageViewModel() { ShowCancel = true; ShowNext = true; } public static WelcomePageViewModel Create() { return ViewModelSource.Create(() => new WelcomePageViewModel()); } public bool CanGoForward { get { return true; } } public void OnGoForward(CancelEventArgs e) { GoForward(); } protected void GoForward() { this.GetRequiredService<IWizardService>().Navigate("PlayTunePage", Model, this); } }

The following table lists Wizard buttons and API used to customize their behavior:

Button WizardPage.Allow_ WizardPage.Show_ Interface Can_ Property On_ Method
Next AllowNext ShowNext ISupportWizardNextCommand CanGoForward OnGoForward
Back AllowBack ShowBack ISupportWizardBackCommand CanGoBack OnGoBack
Cancel AllowCancel ShowCancel ISupportWizardCancelCommand CanCancel OnCancel
Finish AllowFinish ShowFinish ISupportWizardFinishCommand CanFinish OnFinish

This example uses the DevExpress ThemedWindow as a dialog container. In this case, set the ThemedWindowOptions.UseCustomDialogFooter attached property to true to remove the duplicated dialog footer:

XAML
<dx:DialogService.DialogStyle> <Style TargetType="dx:ThemedWindow"> <!-- ... --> <Setter Property="dxi:ThemedWindowOptions.UseCustomDialogFooter" Value="True"/> </Style> </dx:DialogService.DialogStyle>

Files to Review

Documentation

More Examples

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

VM-DrivenWizard/MainWindow.xaml
XAML
<Window x:Class="VM_DrivenWizard.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:VM_DrivenWizard" xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" xmlns:dxi="http://schemas.devexpress.com/winfx/2008/xaml/core/internal" xmlns:dxco="http://schemas.devexpress.com/winfx/2008/xaml/controls" xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm" xmlns:vm="clr-namespace:VM_DrivenWizard.ViewModel" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525" DataContext="{dxmvvm:ViewModelSource Type={x:Type vm:MainWindowViewModel}}"> <dxmvvm:Interaction.Behaviors> <dx:DialogService x:Name="testService"> <dx:DialogService.ViewTemplate> <DataTemplate> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition /> </Grid.RowDefinitions> <GroupBox Header="Wizard options" Margin="5,5,5,20"> <StackPanel Orientation="Horizontal"> <TextBlock VerticalAlignment="Center" Text="Show: " /> <CheckBox IsChecked="{Binding ShowNext, ElementName=wizard}" Content="Next" Margin="5,0,0,0" /> <CheckBox IsChecked="{Binding ShowBack, ElementName=wizard}" Content="Back" Margin="20,0,0,0"/> <CheckBox IsChecked="{Binding ShowCancel, ElementName=wizard}" Content="Cancel" Margin="20,0,0,0"/> <CheckBox IsChecked="{Binding ShowFinish, ElementName=wizard}" Content="Finish" Margin="20,0,0,0"/> <TextBlock VerticalAlignment="Center" Text="Allow: " Margin="40,0,0,0" /> <CheckBox IsChecked="{Binding AllowNext, ElementName=wizard}" Content="Next" Margin="5,0,0,0"/> <CheckBox IsChecked="{Binding AllowBack, ElementName=wizard}" Content="Back" Margin="20,0,0,0" /> <CheckBox IsChecked="{Binding AllowCancel, ElementName=wizard}" Content="Cancel" Margin="20,0,0,0"/> <CheckBox IsChecked="{Binding AllowFinish, ElementName=wizard}" Content="Finish" Margin="20,0,0,0"/> </StackPanel> </GroupBox> <dxco:Wizard x:Name="wizard" Grid.Row="1" AnimationType="SlideHorizontal"> <dxmvvm:Interaction.Behaviors> <dxco:WizardService> <dxco:WizardService.PageGeneratorTemplate> <DataTemplate> <dxco:WizardPage ShowNext="{Binding ShowNext}" ShowBack="{Binding ShowBack}" ShowCancel="{Binding ShowCancel}" ShowFinish="{Binding ShowFinish}" AllowNext="{Binding AllowNext}" AllowBack="{Binding AllowBack}" AllowCancel="{Binding AllowCancel}" AllowFinish="{Binding AllowFinish}" /> </DataTemplate> </dxco:WizardService.PageGeneratorTemplate> </dxco:WizardService> <dx:DXMessageBoxService /> <dxmvvm:EventToCommand EventName="Loaded" Command="{Binding ViewLoadedCommand}" /> </dxmvvm:Interaction.Behaviors> </dxco:Wizard> </Grid> </DataTemplate> </dx:DialogService.ViewTemplate> <dx:DialogService.DialogStyle> <Style TargetType="dx:ThemedWindow"> <Setter Property="WindowStyle" Value="ToolWindow"/> <Setter Property="Width" Value="1000" /> <Setter Property="Height" Value="600" /> <Setter Property="dxi:ThemedWindowOptions.UseCustomDialogFooter" Value="True"/> </Style> </dx:DialogService.DialogStyle> </dx:DialogService> </dxmvvm:Interaction.Behaviors> <Grid> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" > <Button Command="{Binding ShowDialogCommand}" Content="Start Wizard" MinWidth="100" MinHeight="50"/> <TextBlock Text="{Binding Text}" /> </StackPanel> </Grid> </Window>
VM-DrivenWizard/Views/WelcomePage.xaml
XAML
<UserControl x:Class="VM_DrivenWizard.Views.WelcomePage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:viewmodel="clr-namespace:VM_DrivenWizard.ViewModels" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" DataContext="{dxmvvm:ViewModelSource Type=viewmodel:WelcomePageViewModel}"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <DockPanel> <Image DockPanel.Dock="Left" Margin="0,0,16,0" Source="/VM-DrivenWizard;component/Images/WizardControl/wizard-image.png" /> <Grid DockPanel.Dock="Bottom"> <Image Source="/VM-DrivenWizard;component/Images/WizardControl/Have-fun!.png" HorizontalAlignment="Right" Stretch="None" /> <TextBlock Margin="0,0,0,16" FontSize="10" Text="To proceed with the tour, click Next." VerticalAlignment="Bottom" /> </Grid> <StackPanel Margin="0,16,16,16"> <TextBlock TextWrapping="Wrap" MaxWidth="400" HorizontalAlignment="Left" FontSize="20" FontWeight="SemiBold" Text="Welcome to the WPF Product Features Tour" /> <TextBlock TextWrapping="Wrap" MaxWidth="450" HorizontalAlignment="Left" FontSize="10" Text="Thank you for your interest in the WPF Wizard Suite. We hope you'll have some fun during the next few minutes and learn about our new product in the process." /> </StackPanel> </DockPanel> <GroupBox Grid.Column="1" Header="Page options" Margin="2,0,2,2" MinWidth="125"> <StackPanel Orientation="Vertical"> <CheckBox HorizontalAlignment="Left" IsChecked="{Binding ShowNext}" Content="Show next"/> <CheckBox IsChecked="{Binding ShowCancel}" Content="Show cancel"/> </StackPanel> </GroupBox> </Grid> </UserControl>
VM-DrivenWizard/Views/PlayTunePage.xaml
XAML
<UserControl x:Class="VM_DrivenWizard.Views.PlayTunePage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors" xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:viewmodel="clr-namespace:VM_DrivenWizard.ViewModels" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" DataContext="{dxmvvm:ViewModelSource Type=viewmodel:PlayTunePageViewModel}"> <UserControl.Resources> <DataTemplate x:Key="WizardHeaderTemplate"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <TextBlock FontSize="12" FontWeight="Bold" Margin="16,10,0,0" Text="{Binding Header}" /> <TextBlock Grid.Row="1" FontSize="10" Margin="46,2,0,0" Text="{Binding Description}" /> <Image Grid.Column="1" Grid.RowSpan="2" Margin="0,0,16,0" Stretch="None" Source="/VM-DrivenWizard;component/Images/WizardControl/image-61x61.png" /> </Grid> </DataTemplate> </UserControl.Resources> <Grid > <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <DockPanel> <ContentPresenter DockPanel.Dock="Top" Content="{Binding}" ContentTemplate="{StaticResource WizardHeaderTemplate}"/> <Button DockPanel.Dock="Bottom" HorizontalAlignment="Center" Margin="10" MinWidth="65" MinHeight="22" Content="Play" Command="{Binding PlayCommand}"/> <dxe:ListBoxEdit ValueMember="Content" EditValue="{Binding Song, UpdateSourceTrigger=PropertyChanged}" Margin="0,10,0,0" FontSize="10" Height="230"> <dxe:ListBoxEditItem Content="Metallica - Enter Sandman" /> <dxe:ListBoxEditItem Content="Nirvana - Smells Like Teen Spirit" /> <dxe:ListBoxEditItem Content="Pet Shop Boys - West End Girls" /> <dxe:ListBoxEditItem Content="Run D.M.C. - Christmas in Hollis" /> <dxe:ListBoxEditItem Content="Spice Girls - Wannabe" /> <dxe:ListBoxEditItem Content="Backstreet Boys - Show Me the Meaning" /> <dxe:ListBoxEditItem Content="The Prodigy - Firestarter" /> <dxe:ListBoxEditItem Content="The Beatles - Yellow Submarine" /> <dxe:ListBoxEditItem Content="The Rolling Stones - Angie" /> <dxe:ListBoxEditItem Content="Black Eyed Peas - Pump It" /> <dxe:ListBoxEditItem Content="Rihanna - Umbrella" /> <dxe:ListBoxEditItem Content="Linkin Park - From the Inside" /> <dxe:ListBoxEditItem Content="Madonna - Music" /> <dxe:ListBoxEditItem Content="Michael Jackson - Bad" /> <dxe:ListBoxEditItem Content="Kanye West - Stronger" /> <dxe:ListBoxEditItem Content="Gwen Stefani - 4 in the Morning" /> </dxe:ListBoxEdit> </DockPanel> <GroupBox Grid.Column="1" Header="Page options" Margin="2,0,2,2" MinWidth="125"> <StackPanel Orientation="Vertical"> <CheckBox IsChecked="{Binding ShowNext}" Content="Show next"/> <CheckBox IsChecked="{Binding ShowBack}" Content="Show back"/> <CheckBox IsChecked="{Binding ShowCancel}" Content="Show cancel"/> <CheckBox IsChecked="{Binding ShowFinish}" Content="Show finish"/> <CheckBox IsChecked="{Binding AllowBack}" Content="Allow back"/> </StackPanel> </GroupBox> </Grid> </UserControl>
VM-DrivenWizard/Views/CongratulationsPage.xaml
XAML
<UserControl x:Class="VM_DrivenWizard.Views.CongratulationsPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:viewmodel="clr-namespace:VM_DrivenWizard.ViewModels" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" DataContext="{dxmvvm:ViewModelSource Type=viewmodel:CongratulationsPageViewModel}"> <DockPanel> <Image DockPanel.Dock="Left" Source="/VM-DrivenWizard;component/Images/WizardControl/wizard-image.png" /> <TextBlock DockPanel.Dock="Top" TextWrapping="Wrap" Margin="16,16,16,10" FontSize="20" FontWeight="Bold" Text="Congratulations - You've Passed All the Way Through!" /> <TextBlock DockPanel.Dock="Bottom" Margin="16" FontSize="10" Text="To close this wizard, click Finish" /> <TextBlock TextWrapping="Wrap" FontSize="10" Margin="16,0" Text="Thank you for completing this WPF feature tour!" /> </DockPanel> </UserControl>
VM-DrivenWizard/ViewModels/MainWindowViewModel.cs(vb)
C#
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using DevExpress.Mvvm; using DevExpress.Mvvm.POCO; namespace VM_DrivenWizard.ViewModel { public class MainWindowViewModel { public static MainWindowViewModel Create() { return ViewModelSource.Create(() => new MainWindowViewModel()); } protected MainWindowViewModel() { Model = new Model(); } public virtual string Text { get; protected set; } public void ShowDialog() { var wizardResult = this.GetRequiredService<IDialogService>().ShowDialog(MessageButton.OKCancel, "Wizard", this).ToString(); var song = Model.Song; Text = "Wizard result: " + wizardResult + (string.IsNullOrEmpty(song) ? string.Empty : ", you choose " + Model.Song); } Model Model { get; set; } public void ViewLoaded() { this.GetRequiredService<IWizardService>().Navigate("WelcomePage", null, Model, this); } } }
VM-DrivenWizard/ViewModels/WizardViewModelBase.cs(vb)
C#
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using DevExpress.Mvvm; using DevExpress.Mvvm.DataAnnotations; using DevExpress.Mvvm.Native; using DevExpress.Mvvm.POCO; namespace VM_DrivenWizard.ViewModels { public abstract class WizardViewModelBase : ISupportParameter, ISupportWizardCancelCommand { protected WizardViewModelBase() { } public bool CanCancel { get { return GetCanCancel(); } } public virtual Model Model { get; protected set; } object ISupportParameter.Parameter { get { return Model; } set { Model = (Model)value; } } public void OnCancel(CancelEventArgs e) { if (this.GetService<IMessageBoxService>(). ShowMessage("Do you want to exit the WPF feature tour?", "WPF Tour", MessageButton.YesNo, MessageIcon.Question) == MessageResult.No) e.Cancel = true; } protected virtual bool GetCanCancel() { return true; } public virtual bool ShowNext { get; set; } public virtual bool ShowBack { get; set; } public virtual bool ShowCancel { get; set; } public virtual bool ShowFinish { get; set; } public virtual bool AllowNext { get; set; } public virtual bool AllowBack { get; set; } public virtual bool AllowCancel { get; set; } public virtual bool AllowFinish { get; set; } } }
VM-DrivenWizard/ViewModels/WelcomePageViewModel.cs(vb)
C#
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using DevExpress.Mvvm; using DevExpress.Mvvm.POCO; namespace VM_DrivenWizard.ViewModels { public class WelcomePageViewModel : WizardViewModelBase, ISupportWizardNextCommand { protected WelcomePageViewModel() { ShowCancel = true; ShowNext = true; } public static WelcomePageViewModel Create() { return ViewModelSource.Create(() => new WelcomePageViewModel()); } public bool CanGoForward { get { return true; } } public void OnGoForward(CancelEventArgs e) { GoForward(); } protected void GoForward() { this.GetRequiredService<IWizardService>().Navigate("PlayTunePage", Model, this); } } }
VM-DrivenWizard/ViewModels/PlayTunePageViewModel.cs(vb)
C#
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using DevExpress.Mvvm; using DevExpress.Mvvm.POCO; namespace VM_DrivenWizard.ViewModels { public class PlayTunePageViewModel : WizardViewModelBase, ISupportWizardNextCommand, ISupportWizardFinishCommand { public static PlayTunePageViewModel Create() { return ViewModelSource.Create(() => new PlayTunePageViewModel()); } protected PlayTunePageViewModel() { ShowBack = true; ShowCancel = true; ShowNext = true; AllowBack = true; AllowCancel = true; } public string Header { get { return "Step 2 - Play a tune"; } } public string Description { get { return "To make this demo more entertaining, we would like to play a tune for you. Simple choose your favorite track."; } } public void Play() { string text = @"Sorry, but we don't have that song in our library..." + Environment.NewLine; text += @"But we are agree with you that ""{0}"" is an exellent choice."; text = string.Format(text, Model.Song); this.GetService<IMessageBoxService>().ShowMessage(text, "Wizard", MessageButton.OK, MessageIcon.Information); } public bool CanPlay() { return Model != null && !string.IsNullOrEmpty(Model.Song); } public virtual string Song { get; set; } public bool CanGoForward { get { return CanPlay(); } } public bool CanFinish { get { return true; } } protected virtual void OnSongChanged() { Model.Song = Song; } public void OnGoForward(CancelEventArgs e) { this.GetRequiredService<IWizardService>().Navigate("CongratulationsPage", Model, this); } public void OnFinish(CancelEventArgs e) { this.GetService<IMessageBoxService>().ShowMessage("You have finished the tour.", "WPF Tour", MessageButton.OK, MessageIcon.Exclamation); } } }
VM-DrivenWizard/ViewModels/CongratulationsPageViewModel.cs(vb)
C#
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using DevExpress.Mvvm; using DevExpress.Mvvm.POCO; namespace VM_DrivenWizard.ViewModels { public class CongratulationsPageViewModel : WizardViewModelBase, ISupportWizardFinishCommand { protected CongratulationsPageViewModel() { ShowBack = true; ShowCancel = true; ShowFinish = true; AllowBack = true; } public bool CanFinish { get { return true; } } public void OnFinish(CancelEventArgs e) { this.GetService<IMessageBoxService>().ShowMessage("Thank you for completing this WPF feature tour!", "WPF Tour", MessageButton.OK, MessageIcon.Exclamation); } protected override bool GetCanCancel() { return false; } } }

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.