Back to Devexpress

WizardService

wpf-116321-mvvm-framework-services-predefined-set-wizardservice.md

latest37.3 KB
Original Source

WizardService

  • Jul 08, 2024
  • 13 minutes to read

WizardService is an IWizardService implementation that allows you to use the Wizard control in accordance with MVVM.

Note

Before you proceed with the Wizard Service, ensure that you read the following help topic: Services - Getting Started.

To handle clicks on wizard page buttons, implement the following interfaces in ViewModels representing pages, so that the corresponding method is called.

csharp
public abstract class WizardViewModel : ISupportWizardCancelCommand {
        //...
        public bool CanCancel {
            get { return GetCanCancel(); }
        }
        public void OnCancel(CancelEventArgs e) {
            if(this.GetService<IMessageBoxService>().
                ShowMessage("Do you want to exit the Wizard?", "Confirmation", MessageButton.YesNo, MessageIcon.Question) == MessageResult.No)
                e.Cancel = true;
        }
        protected virtual bool GetCanCancel() {
            return true;
        }
    }

Another way is to pass the corresponding events to the main ViewModel.

xaml
<dxco:Wizard DataContext="{dxmvvm:ViewModelSource local:WizardViewModel}" Parameter="{Binding}" ItemsSource="{Binding Items}">
    <!---->
    <dxmvvm:Interaction.Behaviors>
        <dxmvvm:EventToCommand EventName="Cancel" Command="{Binding CancelCommand}" PassEventArgsToCommand="True"/>
    </dxmvvm:Interaction.Behaviors>
    <!---->
</dxco:Wizard>
csharp
public class WizardViewModel {
//...
        public void Cancel(DevExpress.Xpf.Core.CancelRoutedEventArgs ea) {
            if(this.GetService<IMessageBoxService>().
                ShowMessage("Do you want to exit the Wizard?", "Confirmation", MessageButton.YesNo, MessageIcon.Question) == MessageResult.No)
                ea.Cancel = true;
        }
//...
}

The table below lists interfaces, methods, and events corresponding to wizard buttons.

Wizard buttonInterfaceMethodEvent
NextISupportWizardNextCommandISupportWizardNextCommand.OnGoForwardWizard.Next
BackISupportWizardBackCommandISupportWizardBackCommand.OnGoBackWizard.Back
CancelISupportWizardCancelCommandISupportWizardCancelCommand.OnCancelWizard.Cancel
FinishISupportWizardFinishCommandISupportWizardFinishCommand.OnFinishWizard.Finish

To display the desired view in the Wizard control, use the IWizardService.Navigate method.

csharp
public class WizardPageViewModel : ISupportWizardNextCommand {
        //...

        public bool CanGoForward {
            get { return true; }
        }
        public void OnGoForward(CancelEventArgs e) {
            GoForward();
        }

        protected void GoForward() {
            this.GetRequiredService<IWizardService>().Navigate("Next Page", Model, this);
        }
    }

This example demonstrates how to use the WizardService. See Implementation Details for more information.

See also:

How to create a Wizard with pages defined in XAML

How to: Create a wizard based on a collection of view models

View Example

csharp
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;
        }
    }
}
csharp
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);
        }
    }
}
csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace VM_DrivenWizard {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
        }
    }
}
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: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's 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:DXDialogWindow">
                    <Setter Property="WindowStyle" Value="ToolWindow"/>
                    <Setter Property="Width" Value="1000" />
                    <Setter Property="Height" Value="600" />
                </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>
csharp
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; }
    }
}
csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DevExpress.Mvvm.POCO;

namespace VM_DrivenWizard{
    public class Model {
        public string Song { get; set; }
    }
}
csharp
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);
        }
    }
}
csharp
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);
        }
    }
}
xaml
<UserControl x:Class="VM_DrivenWizard.Views.CongratulationsPage"
            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" 
            xmlns:viewmodel="clr-namespace:VM_DrivenWizard.ViewModels"
            xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"
            xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
            xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
            xmlns:dxco="http://schemas.devexpress.com/winfx/2008/xaml/controls"
            mc:Ignorable="d" 
            d:DesignHeight="300" d:DesignWidth="300"
            DataContext="{dxmvvm:ViewModelSource Type=viewmodel:CongratulationsPageViewModel}">

    <DockPanel>
        <dx:DialogFooter>
            <StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
                <dxco:WizardButton VerticalAlignment="Center" Content="Back" dxco:Wizard.IsButtonBack="True" />
                <dxco:WizardButton VerticalAlignment="Center" Content="Finish" dxco:Wizard.IsButtonFinish="True" />
                <dxco:WizardButton VerticalAlignment="Center" Content="Cancel" dxco:Wizard.IsButtonCancel="True" Margin="20,0,0,0" />
            </StackPanel>
        </dx:DialogFooter>
        <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>
xaml
<UserControl x:Class="VM_DrivenWizard.Views.PlayTunePage"
            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" 
            xmlns:viewmodel="clr-namespace:VM_DrivenWizard.ViewModels"
            xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"
            xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
            xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
            xmlns:dxco="http://schemas.devexpress.com/winfx/2008/xaml/controls"
            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>

    <DockPanel>
        <dx:DialogFooter>
            <Grid>
                <GroupBox HorizontalAlignment="Left" Header="This Page's options">
                    <StackPanel Orientation="Horizontal">
                        <CheckBox IsChecked="{Binding ShowNext}" Content="Show next" />
                        <CheckBox IsChecked="{Binding ShowBack}" Content="Show back" Margin="20,0,0,0"/>
                        <CheckBox IsChecked="{Binding ShowCancel}" Content="Show cancel" Margin="20,0,0,0"/>
                        <CheckBox IsChecked="{Binding ShowFinish}" Content="Show finish" Margin="20,0,0,0"/>
                        <CheckBox IsChecked="{Binding AllowBack}" Content="Allow back" Margin="20,0,0,0"/>
                    </StackPanel>
                </GroupBox>
                <StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
                    <dxco:WizardButton VerticalAlignment="Center" Content="Back" dxco:Wizard.IsButtonBack="True" />
                    <dxco:WizardButton VerticalAlignment="Center" Content="Next" dxco:Wizard.IsButtonNext="True" />
                    <dxco:WizardButton VerticalAlignment="Center" Content="Finish" dxco:Wizard.IsButtonFinish="True" />
                    <dxco:WizardButton VerticalAlignment="Center" Content="Cancel" dxco:Wizard.IsButtonCancel="True" Margin="20,0,0,0" />
                </StackPanel>
            </Grid>
        </dx:DialogFooter>
        <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">
            <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>
</UserControl>
xaml
<UserControl x:Class="VM_DrivenWizard.Views.WelcomePage"
            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" 
            xmlns:viewmodel="clr-namespace:VM_DrivenWizard.ViewModels"
            xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"
            xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
            xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
            xmlns:dxco="http://schemas.devexpress.com/winfx/2008/xaml/controls"
            mc:Ignorable="d" 
            d:DesignHeight="300" d:DesignWidth="300"
            DataContext="{dxmvvm:ViewModelSource Type=viewmodel:WelcomePageViewModel}">
    <DockPanel>
        <dx:DialogFooter>
            <Grid>
                <GroupBox HorizontalAlignment="Left" Header="This Page's options">
                    <StackPanel Orientation="Horizontal">
                        <CheckBox HorizontalAlignment="Left" IsChecked="{Binding ShowNext}" Content="Show next"/>
                        <CheckBox IsChecked="{Binding ShowCancel}" Content="Show cancel" Margin="20,0,0,0" />
                    </StackPanel>
                </GroupBox>
                <StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
                    <dxco:WizardButton VerticalAlignment="Center" Content="Next" dxco:Wizard.IsButtonNext="True" />
                    <dxco:WizardButton VerticalAlignment="Center" Content="Cancel" dxco:Wizard.IsButtonCancel="True" Margin="20,0,0,0" />
                </StackPanel>
            </Grid>
        </dx:DialogFooter>
        <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>
</UserControl>
vb
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Linq
Imports System.Text
Imports System.Threading.Tasks
Imports DevExpress.Mvvm
Imports DevExpress.Mvvm.POCO

Namespace VM_DrivenWizard.ViewModels
    Public Class CongratulationsPageViewModel
        Inherits WizardViewModelBase
        Implements ISupportWizardFinishCommand

        Protected Sub New()
            ShowBack = True
            ShowCancel = True
            ShowFinish = True
            AllowBack = True
        End Sub
        Public ReadOnly Property CanFinish() As Boolean Implements ISupportWizardFinishCommand.CanFinish
            Get
                Return True
            End Get
        End Property

        Public Sub OnFinish(ByVal e As CancelEventArgs) Implements ISupportWizardFinishCommand.OnFinish
            Me.GetService(Of IMessageBoxService)().ShowMessage("Thank you for completing this WPF feature tour!", "WPF Tour", MessageButton.OK, MessageIcon.Exclamation)
        End Sub
        Protected Overrides Function GetCanCancel() As Boolean
            Return False
        End Function
    End Class
End Namespace
vb
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Linq
Imports System.Text
Imports System.Threading.Tasks
Imports DevExpress.Mvvm
Imports DevExpress.Mvvm.POCO

Namespace VM_DrivenWizard.ViewModels
    Public Class WelcomePageViewModel
        Inherits WizardViewModelBase
        Implements ISupportWizardNextCommand

        Protected Sub New()
            ShowCancel = True
            ShowNext = True
        End Sub
        Public Shared Function Create() As WelcomePageViewModel
            Return ViewModelSource.Create(Function() New WelcomePageViewModel())
        End Function
        Public ReadOnly Property CanGoForward() As Boolean Implements ISupportWizardNextCommand.CanGoForward
            Get
                Return True
            End Get
        End Property
        Public Sub OnGoForward(ByVal e As CancelEventArgs) Implements ISupportWizardNextCommand.OnGoForward
            GoForward()
        End Sub
        Protected Sub GoForward()
            Me.GetRequiredService(Of IWizardService)().Navigate("PlayTunePage", Model, Me)
        End Sub
    End Class
End Namespace
vb
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Data
Imports System.Windows.Documents
Imports System.Windows.Input
Imports System.Windows.Media
Imports System.Windows.Media.Imaging
Imports System.Windows.Navigation
Imports System.Windows.Shapes

Namespace VM_DrivenWizard
    ''' <summary>
    ''' Interaction logic for MainWindow.xaml
    ''' </summary>
    Partial Public Class MainWindow
        Inherits Window

        Public Sub New()
            InitializeComponent()
        End Sub
    End Class
End Namespace
vb
Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Linq
Imports System.Text
Imports System.Threading
Imports System.Threading.Tasks
Imports DevExpress.Mvvm
Imports DevExpress.Mvvm.POCO

Namespace VM_DrivenWizard.ViewModel
    Public Class MainWindowViewModel
        Public Shared Function Create() As MainWindowViewModel
            Return ViewModelSource.Create(Function() New MainWindowViewModel())
        End Function

        Protected Sub New()
            Model = New Model()
        End Sub

        Private privateText As String
        Public Overridable Property Text() As String
            Get
                Return privateText
            End Get
            Protected Set(ByVal value As String)
                privateText = value
            End Set
        End Property

        Public Sub ShowDialog()
            Dim wizardResult = Me.GetRequiredService(Of IDialogService)().ShowDialog(MessageButton.OKCancel, "Wizard", Me).ToString()
            Dim song = Model.Song
            Text = "Wizard result: " & wizardResult & (If(String.IsNullOrEmpty(song), String.Empty, ", you choose " & Model.Song))
        End Sub

        Private Property Model() As Model
        Public Sub ViewLoaded()
            Me.GetRequiredService(Of IWizardService)().Navigate("WelcomePage", Nothing, Model, Me)
        End Sub
    End Class
End Namespace
vb
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Linq
Imports System.Text
Imports System.Threading.Tasks
Imports DevExpress.Mvvm
Imports DevExpress.Mvvm.DataAnnotations
Imports DevExpress.Mvvm.Native
Imports DevExpress.Mvvm.POCO

Namespace VM_DrivenWizard.ViewModels
    Public MustInherit Class WizardViewModelBase
        Implements ISupportParameter, ISupportWizardCancelCommand

        Protected Sub New()
        End Sub
        Public ReadOnly Property CanCancel() As Boolean Implements ISupportWizardCancelCommand.CanCancel
            Get
                Return GetCanCancel()
            End Get
        End Property
        Private privateModel As Model
        Public Overridable Property Model() As Model
            Get
                Return privateModel
            End Get
            Protected Set(ByVal value As Model)
                privateModel = value
            End Set
        End Property
        Private Property ISupportParameter_Parameter() As Object Implements ISupportParameter.Parameter
            Get
                Return Model
            End Get
            Set(ByVal value As Object)
                Model = DirectCast(value, Model)
            End Set
        End Property
        Public Sub OnCancel(ByVal e As CancelEventArgs) Implements ISupportWizardCancelCommand.OnCancel
            If Me.GetService(Of IMessageBoxService)().ShowMessage("Do you want to exit the WPF feature tour?", "WPF Tour", MessageButton.YesNo, MessageIcon.Question) = MessageResult.No Then
                e.Cancel = True
            End If
        End Sub
        Protected Overridable Function GetCanCancel() As Boolean
            Return True
        End Function
        Public Overridable Property ShowNext() As Boolean
        Public Overridable Property ShowBack() As Boolean
        Public Overridable Property ShowCancel() As Boolean
        Public Overridable Property ShowFinish() As Boolean
        Public Overridable Property AllowNext() As Boolean
        Public Overridable Property AllowBack() As Boolean
        Public Overridable Property AllowCancel() As Boolean
        Public Overridable Property AllowFinish() As Boolean
    End Class
End Namespace
vb
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Linq
Imports System.Text
Imports System.Threading.Tasks
Imports DevExpress.Mvvm
Imports DevExpress.Mvvm.POCO

Namespace VM_DrivenWizard.ViewModels
    Public Class PlayTunePageViewModel
        Inherits WizardViewModelBase
        Implements ISupportWizardNextCommand, ISupportWizardFinishCommand

        Public Shared Function Create() As PlayTunePageViewModel
            Return ViewModelSource.Create(Function() New PlayTunePageViewModel())
        End Function
        Protected Sub New()
            ShowBack = True
            ShowCancel = True
            ShowNext = True
            AllowBack = True
            AllowCancel = True
        End Sub
        Public ReadOnly Property Header() As String
            Get
                Return "Step 2 - Play a tune"
            End Get
        End Property
        Public ReadOnly Property Description() As String
            Get
                Return "To make this demo more entertaining, we would like to play a tune for you. Simple choose your favorite track."
            End Get
        End Property

        Public Sub Play()
            Dim text As String = "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)
            Me.GetService(Of IMessageBoxService)().ShowMessage(text, "Wizard", MessageButton.OK, MessageIcon.Information)
        End Sub
        Public Function CanPlay() As Boolean
            Return Model IsNot Nothing AndAlso Not String.IsNullOrEmpty(Model.Song)
        End Function
        Public Overridable Property Song() As String

        Public ReadOnly Property CanGoForward() As Boolean Implements ISupportWizardNextCommand.CanGoForward
            Get
                Return CanPlay()
            End Get
        End Property

        Public ReadOnly Property CanFinish() As Boolean Implements ISupportWizardFinishCommand.CanFinish
            Get
                Return True
            End Get
        End Property

        Protected Overridable Sub OnSongChanged()
            Model.Song = Song
        End Sub

        Public Sub OnGoForward(ByVal e As CancelEventArgs) Implements ISupportWizardNextCommand.OnGoForward
            Me.GetRequiredService(Of IWizardService)().Navigate("CongratulationsPage", Model, Me)
        End Sub
        Public Sub OnFinish(ByVal e As CancelEventArgs) Implements ISupportWizardFinishCommand.OnFinish
            Me.GetService(Of IMessageBoxService)().ShowMessage("You have finished the tour.", "WPF Tour", MessageButton.OK, MessageIcon.Exclamation)
        End Sub
    End Class
End Namespace
vb
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Threading.Tasks
Imports DevExpress.Mvvm.POCO

Namespace VM_DrivenWizard
    Public Class Model
        Public Property Song() As String
    End Class
End Namespace