Code-Only: Winforms Wizard Series Article 3 (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 Panel : Implements IWizardPanel
    Private _prev As Boolean = False
    Private _next As Boolean = False
    Private _finish As Boolean = False
    Private _description 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.Text = description
       
        InitializeComponent()
    End Sub
   
    Private Sub InitializeComponent()
        _description.Dock = DockStyle.Fill
        Me.Controls.Add(_description)
    End Sub
   
    Public ReadOnly Property ShowNavigatePrevious() As Boolean Implements IWizardPanel.ShowNavigatePrevious
        Get
            Return _prev
        End Get
    End Property
   
    Public ReadOnly Property ShowNavigateNext() As Boolean Implements IWizardPanel.ShowNavigateNext
        Get
            Return _next
        End Get
    End Property
   
    Public ReadOnly Property ShowNavigateFinish() As Boolean Implements IWizardPanel.ShowNavigateFinish
        Get
            Return _finish
        End Get
    End Property
End Class

Public Class WizardPanelWithNavigation : Inherits Panel : Implements IWizardPanel, IWizardNavigation
    Private _prev As Boolean = False
    Private _next As Boolean = False
    Private _finish As Boolean = False
    Private _name As String
    Private _nextPanel As String
    Private _prevPanel As String
   
    Private _description As New Label()
   
    Public Sub New(name As String, description As String, prevPanel As String, nextPanel As String, showfinish As Boolean)
        _prev = Not prevPanel Is Nothing
        _next = Not nextPanel Is Nothing
        _finish = showfinish
        _description.Text = description
        _name = name
        _nextPanel = nextPanel
        _prevPanel = prevPanel
       
        InitializeComponent()
    End Sub
   
    Public Sub InitializeComponent()
        _description.Dock = DockStyle.Fill
        Me.Controls.Add(_description)
    End Sub
   
    Public ReadOnly Property ShowNavigatePrevious() As Boolean Implements IWizardPanel.ShowNavigatePrevious
        Get
            Return _prev
        End Get
    End Property
   
    Public ReadOnly Property ShowNavigateNext() As Boolean Implements IWizardPanel.ShowNavigateNext
        Get
            Return _next
        End Get
    End Property
   
    Public ReadOnly Property ShowNavigateFinish() As Boolean Implements IWizardPanel.ShowNavigateFinish
        Get
            Return _finish
        End Get
    End Property

    Public ReadOnly Property SupportNamedNavigation() As Boolean Implements IWizardNavigation.SupportNamedNavigation
        Get
            Return True
        End Get
    End Property
   
    Public ReadOnly Property NavigateName() As String Implements IWizardNavigation.NavigateName
        Get
            Return _name
        End Get
    End Property

    Public ReadOnly Property NavigatePreviousTarget() As String Implements IWizardNavigation.NavigatePreviousTarget
        Get
            Return _prevPanel
        End Get
    End Property

    Public ReadOnly Property NavigateNextTarget() As String Implements IWizardNavigation.NavigateNextTarget
        Get
            Return _nextPanel
        End Get
    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)