Code-Only: Winforms Wizard Series Article 4 (VB .NET)

Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.Threading
Imports System.Windows.Forms

Public Interface IWizardDialog
    ReadOnly Property NavigatePrevious() As Control
    ReadOnly Property NavigateNext() As Control
    ReadOnly Property NavigateFinish() As Control
    ReadOnly Property UIRoot() As Control
    Property Display() As Boolean
End Interface

Public Interface IWizardPanel
    ReadOnly Property ShowNavigatePrevious() As Boolean
    ReadOnly Property ShowNavigateNext() As Boolean
    ReadOnly Property ShowNavigateFinish() As Boolean
End Interface

Public Interface IWizardNavigation
    ReadOnly Property SupportNamedNavigation() As Boolean
    ReadOnly Property NavigateName() As String
    ReadOnly Property NavigatePreviousTarget() As String
    ReadOnly Property NavigateNextTarget() As String
End Interface

Public Class WizardController : Inherits ApplicationContext
    Private _complete As Boolean = False
    Private _wizardIndex As Integer = -1
    Private _wizardDialog As IWizardDialog = Nothing
    Private _wizardPanels As New ArrayList()
    Private _nameMap As New Hashtable()
   
    Public Sub New()
    End Sub
   
    Public Sub SetDialog(dialog As Form)
        Try
            _wizardDialog = DirectCast(dialog, IWizardDialog)
        Catch
            Throw New Exception("Wizard dialogs must support IWizardDialog")
        End Try
       
        If _wizardDialog.NavigatePrevious Is Nothing Then Throw New Exception("Wizard dialogs must have a Previous Button")
        If _wizardDialog.NavigateNext Is Nothing Then Throw New Exception("Wizard dialogs must have a Next Button")
        If _wizardDialog.NavigateFinish Is Nothing Then Throw New Exception("Wizard dialogs must have a Finish Button")
        If _wizardDialog.UIRoot Is Nothing Then Throw New Exception("Wizard dialogs must have a non null UI Root")
       
        AddHandler _wizardDialog.NavigatePrevious.Click, AddressOf Me.Wizard_NavigatePrevious
        AddHandler _wizardDialog.NavigateNext.Click, AddressOf Me.Wizard_NavigateNext
        AddHandler _wizardDialog.NavigateFinish.Click, AddressOf Me.Wizard_NavigateFinish
        AddHandler dialog.Closing, AddressOf Me.Wizard_Closing
    End Sub
   
    Public Sub AddPanel(pnl As Control)
        Try
            Dim iwp As IWizardPanel = DirectCast(pnl, IWizardPanel)
           
            Try
                Dim iwn As IWizardNavigation = DirectCast(pnl, IWizardNavigation)
               
                If _nameMap.ContainsKey(iwn.NavigateName) Then Throw New Exception("Wizard Navigation Panels can't share names.")
                _nameMap(iwn.NavigateName) = iwn
            Catch
                ' Do Nothing
            End Try

            _wizardPanels.Add(iwp)
        Catch
            Throw New Exception("Wizard panels must support IWizardPanel")
        End Try
    End Sub
   
    Public ReadOnly Property Complete() As Boolean
        Get
            Return _complete
        End Get
    End Property
   
    Public ReadOnly Property Panels() As ArrayList
        Get
            Return _wizardPanels
        End Get
    End Property
   
    Public Sub Wizard_Closing(Sender As Object, E As CancelEventArgs)
        MessageBox.Show("You must complete the wizard in order to exit.")
        E.Cancel = True
    End Sub
   
    Public Sub Wizard_NavigateFinish(Sender As Object, E As EventArgs)
        ' this could be fired anywhere in case you have an opt out
        ' early button on any of your forms.
   
        _wizardDialog.UIRoot.Controls.Clear()
        _wizardDialog.Display = False
        _complete = True
       
        ExitThread()
    End Sub
   
    Public Sub Wizard_NavigateNext(Sender As Object, E As EventArgs)
        Try
            Dim iwn As IWizardNavigation = DirectCast(_wizardPanels(_wizardIndex), IWizardNavigation)
           
            If iwn.SupportNamedNavigation
                If _nameMap.ContainsKey(iwn.NavigateNextTarget)
                    _wizardIndex = _wizardPanels.IndexOf(_nameMap(iwn.NavigateNextTarget))
                Else
                    _wizardIndex = _wizardPanels.Count
                End If
            Else
                _wizardIndex += 1
            End If
        Catch
            _wizardIndex += 1
        End Try
       
        If _wizardIndex = _wizardPanels.Count
            Wizard_NavigateFinish(Sender, E) ' This should't happen if your dialogs are correct
            Return
        End If
       

        Try
            Dim newPanel As Control = DirectCast(_wizardPanels(_wizardIndex), Control)
            InitPanel(newPanel)
        Catch
            ' Do Nothing
        End Try
    End Sub
   
    Public Sub Wizard_NavigatePrevious(Sender As Object, E As EventArgs)
        Try
            Dim iwn As IWizardNavigation = DirectCast(_wizardPanels(_wizardIndex), IWizardNavigation)
           
            If iwn.SupportNamedNavigation
                If _nameMap.ContainsKey(iwn.NavigatePreviousTarget)
                    _wizardIndex = _wizardPanels.IndexOf(_nameMap(iwn.NavigatePreviousTarget))
                Else
                    Return
                End If
            Else
                If _wizardIndex > 0 Then _wizardIndex -= 1 Else Return
            End If
        Catch
            If _wizardIndex > 0 Then _wizardIndex -= 1 Else Return
        End Try
       
        Try
            Dim newPanel As Control = DirectCast(_wizardPanels(_wizardIndex), Control)
            InitPanel(newPanel)
        Catch
            ' Do Nothing
        End Try
    End Sub
   
    Public Sub StartWizard()
        If _wizardPanels.Count = 0 Then Throw New Exception("Must add panels to the wizard")
        If _wizardIndex <> -1 AndAlso Not _complete Then Throw New Exception("Wizard has already been started")
       
        _complete = False
        _wizardIndex = 0
        Try
            Dim startPanel As Control = DirectCast(_wizardPanels(_wizardIndex), Control)
            InitPanel(startPanel)
        Catch
        End Try
       
        _wizardDialog.Display = True
    End Sub
   
    Public Sub InitPanel(wizardPanel As Control)
        wizardPanel.Dock = DockStyle.Fill
       
        Try
            Dim iwp As IWizardPanel = DirectCast(wizardPanel, IWizardPanel)
           
            _wizardDialog.NavigatePrevious.Enabled = iwp.ShowNavigatePrevious
            _wizardDialog.NavigateNext.Enabled = iwp.ShowNavigateNext
            _wizardDialog.NavigateFinish.Enabled = iwp.ShowNavigateFinish
        Catch
        End Try
       
        _wizardDialog.UIRoot.Controls.Clear()
        _wizardDialog.UIRoot.Controls.Add(wizardPanel)
    End Sub
End Class

Public Class WizardPanel : Inherits DesignablePanel
    Protected _description As String
    Protected _lblDescription As New Label()
   
    Public Sub New(description As String, showprev As Boolean, shownext As Boolean, showfinish As Boolean)
        _prev = showprev
        _next = shownext
        _finish = showfinish
        _description = description
       
        InitializeComponent()
    End Sub
   
    Private Sub InitializeComponent()
        _lblDescription.Dock = DockStyle.Fill
        _lblDescription.Text = _description
        Me.Controls.Add(_lblDescription)
    End Sub
End Class

Public Class WizardPanelWithNavigation : Inherits DesignablePanelWithNavigation
    Protected _description As String
    Protected _lblDescription As New Label()

    Public Sub New(name As String, description As String, prevPanel As String, nextPanel As String, showfinish As Boolean)
        _name = name
        _nextPanel = nextPanel
        _prevPanel = prevPanel
        _finish = showfinish
        _description = description
       
        InitializeComponent()
    End Sub
   
    Private Sub InitializeComponent()
        _lblDescription.Dock = DockStyle.Fill
        _lblDescription.Text = _description
        Me.Controls.Add(_lblDescription)
    End Sub
End Class

Public Class DesignablePanel : Inherits UserControl : Implements IWizardPanel
    Protected _prev As Boolean = False
    Protected _next As Boolean = False
    Protected _finish As Boolean = False

    Public Sub New()
    End Sub

    <Browsable(False)> Public Overridable ReadOnly Property ShowNavigatePrevious() As Boolean Implements IWizardPanel.ShowNavigatePrevious
        Get
            Return _prev
        End Get
    End Property
   
    <Browsable(False)> Public Overridable ReadOnly Property ShowNavigateNext() As Boolean Implements IWizardPanel.ShowNavigateNext
        Get
            Return _next
        End Get
    End Property
   
    <Browsable(False)> Public Overridable ReadOnly Property ShowNavigateFinish() As Boolean Implements IWizardPanel.ShowNavigateFinish
        Get
            Return _finish
        End Get
    End Property

    < _
        Browsable(True), _
        Category("Wizard"), _
        Description("Determines if the Previous button is activated when this panel is displayed") _
    > _
    Public Overridable Property NavigatePrevious() As Boolean
        Get
            Return _prev
        End Get
        Set(Value As Boolean)
            _prev = Value
        End Set
    End Property

    < _
        Browsable(True), _
        Category("Wizard"), _
        Description("Determines if the Next button is activated when this panel is displayed") _
    > _
    Public Overridable Property NavigateNext() As Boolean
        Get
            Return _next
        End Get
        Set(Value As Boolean)
            _next = Value
        End Set
    End Property
   
    < _
        Browsable(True), _
        Category("Wizard"), _
        Description("Determines if the Finish button is activated when this panel is displayed") _
    > _
    Public Overridable Property NavigateFinish() As Boolean
        Get
            Return _finish
        End Get
        Set(Value As Boolean)
            _finish = Value
        End Set
    End Property
End Class

Public Class DesignablePanelWithNavigation : Inherits DesignablePanel : Implements IWizardNavigation
    Protected _name As String
    Protected _nextPanel As String
    Protected _prevPanel As String
   
    Public Sub New()
    End Sub
   
    <Browsable(False)> Public Overridable ReadOnly Property SupportNamedNavigation() As Boolean Implements IWizardNavigation.SupportNamedNavigation
        Get
            Return (Not _nextPanel Is Nothing Or Not _prevPanel Is Nothing)
        End Get
    End Property
   
    <Browsable(False)> Public Overridable ReadOnly Property NavigateName() As String Implements IWizardNavigation.NavigateName
        Get
            Return _name
        End Get
    End Property

    <Browsable(False)> Public Overridable ReadOnly Property NavigatePreviousTarget() As String Implements IWizardNavigation.NavigatePreviousTarget
        Get
            Return _prevPanel
        End Get
    End Property

    <Browsable(False)> Public Overridable ReadOnly Property NavigateNextTarget() As String Implements IWizardNavigation.NavigateNextTarget
        Get
            Return _nextPanel
        End Get
    End Property

    <Browsable(False)> Public Overrides ReadOnly Property ShowNavigatePrevious() As Boolean
        Get
            Return Not _prevPanel Is Nothing
        End Get
    End Property
   
    <Browsable(False)> Public Overrides ReadOnly Property ShowNavigateNext() As Boolean
        Get
            Return Not _nextPanel Is Nothing
        End Get
    End Property

    <Browsable(False)> Public Overrides Property NavigatePrevious() As Boolean
        Get
            Return ShowNavigatePrevious
        End Get
        Set(Value As Boolean)
        End Set
    End Property

    <Browsable(False)> Public Overrides Property NavigateNext() As Boolean
        Get
            Return ShowNavigateNext
        End Get
        Set(Value As Boolean)
        End Set
    End Property

    < _
        Browsable(True), _
        Category("Wizard"), _
        Description("Sets the name of this wizard panel for navigation purposes.  Each panel" & _
                    "within a WizardController must have a unique name.") _
    > _
    Public Overridable Property PanelName() As String
        Get
            Return _name
        End Get
        Set(Value As String)
            _name = Value
        End Set
    End Property

    < _
        Browsable(True), _
        Category("Wizard"), _
        Description("Sets the name of the next panel in the series.  This property, if set, enables" & _
                    "the SupportNamedNavigation feature and the display of the Next button within" & _
                    "a WizardDialog") _
    > _
    Public Overridable Property NextTargetName() As String
        Get
            Return _nextPanel
        End Get
        Set(Value As String)
            _nextPanel = Value
        End Set
    End Property

    < _
        Browsable(True), _
        Category("Wizard"), _
        Description("Sets the name of the previous panel in the series.  This property, if set, enables" & _
                    "the SupportNamedNavigation feature and the display of the Previous button within" & _
                    "a WizardDialog") _
    > _
    Public Overridable Property PreviousTargetName() As String
        Get
            Return _prevPanel
        End Get
        Set(Value As String)
            _prevPanel = Value
        End Set
    End Property
End Class

Public Class WizardTestDialog : Inherits Form : Implements IWizardDialog
    Private _topPanel As New Panel()
    Private _bottomPanel As New Panel()
   
    Private _previousButton As New Button()
    Private _nextButton As New Button()
    Private _finishButton As New Button()
   
    Private _title As String
   
    Public Sub New(title As String)
        _title = title
        InitializeComponent()
    End Sub
   
    Public ReadOnly Property NavigatePrevious() As Control Implements IWizardDialog.NavigatePrevious
        Get
            Return _previousButton
        End Get
    End Property
   
    Public ReadOnly Property NavigateNext() As Control Implements IWizardDialog.NavigateNext
        Get
            Return _nextButton
        End Get
    End Property
   
    Public ReadOnly Property NavigateFinish() As Control Implements IWizardDialog.NavigateFinish
        Get
            Return _finishButton
        End Get
    End Property
   
    Public ReadOnly Property UIRoot() As Control Implements IWizardDialog.UIRoot
        Get
            Return _topPanel
        End Get
    End Property
   
    Public Property Display() As Boolean Implements IWizardDialog.Display
        Get
            Return Me.Visible
        End Get
        Set(Value As Boolean)
            Me.Visible = Value
        End Set
    End Property
   
    Private Sub InitializeComponent()
        _bottomPanel.Height = 30
        _bottomPanel.Dock = DockStyle.Bottom
       
        _topPanel.Dock = DockStyle.Fill
       
        Me.Text = _title
        Me.Controls.AddRange(New Control() { _topPanel, _bottomPanel })
       
        _finishButton.Text = "Finish"
        _finishButton.Left = _bottomPanel.Width - (_finishButton.Width + 10)
        _finishButton.Anchor = AnchorStyles.Right
       
        _nextButton.Text = "Next"
        _nextButton.Left = _finishButton.Left - (_nextButton.Width + 5)
        _nextButton.Anchor = AnchorStyles.Right
       
        _previousButton.Text = "Previous"
        _previousButton.Left = _nextButton.Left - (_previousButton.Width + 5)
        _previousButton.Anchor = AnchorStyles.Right
       
        _bottomPanel.Controls.AddRange(New Control() { _previousButton, _nextButton, _finishButton })
    End Sub
End Class

Public Class WizardTester
    <STAThread()> _
    Shared Sub Main()
        Dim controller As New WizardController
        controller.SetDialog(new WizardTestDialog("What do you want?"))
        controller.AddPanel(New WizardPanel("foo 1", False, True, False))
        controller.AddPanel(New WizardPanel("foo 2", True, True, False))
        controller.AddPanel(New WizardPanel("foo 3", True, True, False))
        controller.AddPanel(New WizardPanel("foo 4", True, True, True))
        controller.AddPanel(New WizardPanel("foo 5", True, False, True))

        controller.StartWizard()
        Application.Run(controller)

        controller = New WizardController()
        controller.SetDialog(New WizardTestDialog("What do you want?"))
        controller.AddPanel(New WizardPanelWithNavigation("Panel 1", "Welcome Screen!",     Nothing, "Panel 3", False))
        controller.AddPanel(New WizardPanelWithNavigation("Panel 2", "License Agreement!",  "Panel 3", "Panel 4", False))
        controller.AddPanel(New WizardPanelWithNavigation("Panel 3", "Install Options",     "Panel 1", "Panel 2", False))
        controller.AddPanel(New WizardPanelWithNavigation("Panel 4", "Confirmation Screen", "Panel 2", "Panel 5", False))
        controller.AddPanel(New WizardPanelWithNavigation("Panel 5", "Install Now!",        Nothing, Nothing, True))

        controller.StartWizard()
        Application.Run(controller)
    End Sub
End Class

Published Monday, April 26, 2004 1:40 AM by Justin Rogers

Comments

No Comments

Leave a Comment

(required) 
(required) 
(optional)
(required)