Stuck Between Interface & Abstract Class

I am in the process of converting a VB6 application with 60 forms to VB.Net. Each form has many public variables, instead of properties.

Many public subs and functions can work with several different forms. I could not keep the form type variables as it obviously would not compile. I first tried to use an Interface but then learned they don't support variables. Now I have an abstract form class which I am adding the methods and functions as overridable. Now it is complaining that the abstract form doesn't contain the controls of the child form.

I created a function which returns the abstract class, returning the child form class depending on the form's name, passed through my abstract form class. Now, I want to use that returned child form class in a public function but it complains because I have not DirectCast it to that child form class which has the controls.

I wish I could have a conditional right-side assignment, and am trying to figure how to use DirectCast with a select-case statement.

I am stuck in a function that used to take a simple System.Windows.Forms.Form that would work with any form passed to it, and compiling was not a problem. Now in a more strict environment I need to pass in any one of several forms and then have an object variable of the child class form. I believe I want to DirectCast it once and which there was a variable / logical way I could use one DirectCast that would cast it to the correct child class.

An example of what won't compile, my form1 and form2 both have a txtFirstName control.

Public Function Test() As 
   Dim f As f_AbstractForm 'any form that calls this 
   f = GetFormByName(f.Name) 'returns child form object which inherits f_AbstractForm, function return type is f_AbstractForm 

   ' Next line is the problem.
   ' Compiler doesn't like that txtFirstName is not on f_AbstractForm, so I need to DirectCast before this line, 
   ' but stuck on how to do this. If form1 calls Test() then I want it to return a form1, if form2 calls Test() then I need it to return form2
   f.txtFirstName.Text = ""  
   ...
End Function

Open in new window


This is my first post since joining Experts Exchange, any help or advice will be appreciated!
Richie MaddenOwner-OperatorAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

it_saigeDeveloperCommented:
Here is one relatively simple example to display the relationship and how you would use casting to access properties on child instances.
MainForm.vb -
Public Class MainForm
	Private Sub OnClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click, Button3.Click, Button2.Click, Button1.Click
		If TypeOf sender Is Button Then
			Dim btn = DirectCast(sender, Button)
			Dim form As New BaseForm
			If btn.Equals(Button1) Then
				form = New ChildOne()
				form.Show()
			ElseIf btn.Equals(Button2) Then
				form = New ChildTwo()
				form.Show()
			ElseIf btn.Equals(Button3) Then
				form = New ChildThree()
				form.Show()
			ElseIf btn.Equals(Button4) Then
				form = New ChildFour()
				form.Show()
			End If
		End If
	End Sub
End Class

Open in new window

MainForm.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class MainForm
    Inherits System.Windows.Forms.Form

    'Form overrides dispose to clean up the component list.
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
		Me.Button1 = New System.Windows.Forms.Button()
		Me.Button2 = New System.Windows.Forms.Button()
		Me.Button3 = New System.Windows.Forms.Button()
		Me.Button4 = New System.Windows.Forms.Button()
		Me.SuspendLayout()
		'
		'Button1
		'
		Me.Button1.Location = New System.Drawing.Point(13, 13)
		Me.Button1.Name = "Button1"
		Me.Button1.Size = New System.Drawing.Size(75, 23)
		Me.Button1.TabIndex = 0
		Me.Button1.Text = "Button1"
		Me.Button1.UseVisualStyleBackColor = True
		'
		'Button2
		'
		Me.Button2.Location = New System.Drawing.Point(13, 43)
		Me.Button2.Name = "Button2"
		Me.Button2.Size = New System.Drawing.Size(75, 23)
		Me.Button2.TabIndex = 1
		Me.Button2.Text = "Button2"
		Me.Button2.UseVisualStyleBackColor = True
		'
		'Button3
		'
		Me.Button3.Location = New System.Drawing.Point(13, 73)
		Me.Button3.Name = "Button3"
		Me.Button3.Size = New System.Drawing.Size(75, 23)
		Me.Button3.TabIndex = 2
		Me.Button3.Text = "Button3"
		Me.Button3.UseVisualStyleBackColor = True
		'
		'Button4
		'
		Me.Button4.Location = New System.Drawing.Point(13, 103)
		Me.Button4.Name = "Button4"
		Me.Button4.Size = New System.Drawing.Size(75, 23)
		Me.Button4.TabIndex = 3
		Me.Button4.Text = "Button4"
		Me.Button4.UseVisualStyleBackColor = True
		'
		'MainForm
		'
		Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.ClientSize = New System.Drawing.Size(284, 262)
		Me.Controls.Add(Me.Button4)
		Me.Controls.Add(Me.Button3)
		Me.Controls.Add(Me.Button2)
		Me.Controls.Add(Me.Button1)
		Me.Name = "MainForm"
		Me.Text = "MainForm"
		Me.ResumeLayout(False)

	End Sub
	Friend WithEvents Button1 As System.Windows.Forms.Button
	Friend WithEvents Button2 As System.Windows.Forms.Button
	Friend WithEvents Button3 As System.Windows.Forms.Button
	Friend WithEvents Button4 As System.Windows.Forms.Button
End Class

Open in new window

BaseForm.vb -
Public Class BaseForm
	Public Property Title() As String

	Private Sub OnLoad(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
		If TypeOf sender Is ChildOne Then
			Text = DirectCast(sender, ChildOne).ChildOneProperty
		ElseIf TypeOf sender Is ChildTwo Then
			Text = DirectCast(sender, ChildTwo).ChildTwoProperty
		ElseIf TypeOf sender Is ChildThree Then
			Text = DirectCast(sender, ChildThree).ChildThreeProperty
		ElseIf TypeOf sender Is ChildFour Then
			Text = DirectCast(sender, ChildFour).ChildFourProperty
		End If
	End Sub
End Class

Open in new window

BaseForm.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class BaseForm
	Inherits System.Windows.Forms.Form

	'Form overrides dispose to clean up the component list.
	<System.Diagnostics.DebuggerNonUserCode()> _
	Protected Overrides Sub Dispose(ByVal disposing As Boolean)
		Try
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
		Finally
			MyBase.Dispose(disposing)
		End Try
	End Sub

	'Required by the Windows Form Designer
	Private components As System.ComponentModel.IContainer

	'NOTE: The following procedure is required by the Windows Form Designer
	'It can be modified using the Windows Form Designer.  
	'Do not modify it using the code editor.
	<System.Diagnostics.DebuggerStepThrough()> _
	Private Sub InitializeComponent()
		Me.SuspendLayout()
		'
		'BaseForm
		'
		Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.ClientSize = New System.Drawing.Size(284, 262)
		Me.Name = "BaseForm"
		Me.Text = "Form1"
		Me.ResumeLayout(False)

	End Sub

End Class

Open in new window

ChildOne.vb -
Public Class ChildOne
	Public Property ChildOneProperty() As String

	Public Sub New()

		' This call is required by the designer.
		InitializeComponent()

		' Add any initialization after the InitializeComponent() call.
		ChildOneProperty = "Child One"
	End Sub
End Class

Open in new window

ChildOne.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class ChildOne
	Inherits BaseForm

    'Form overrides dispose to clean up the component list.
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
        components = New System.ComponentModel.Container
        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
        Me.Text = "ChildOne"
    End Sub
End Class

Open in new window

ChildTwo.vb -
Public Class ChildTwo
	Public Property ChildTwoProperty() As String

	Public Sub New()

		' This call is required by the designer.
		InitializeComponent()

		' Add any initialization after the InitializeComponent() call.
		ChildTwoProperty = "Child Two"
	End Sub
End Class

Open in new window

ChildTwo.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class ChildTwo
	Inherits BaseForm

	'Form overrides dispose to clean up the component list.
	<System.Diagnostics.DebuggerNonUserCode()> _
	Protected Overrides Sub Dispose(ByVal disposing As Boolean)
		Try
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
		Finally
			MyBase.Dispose(disposing)
		End Try
	End Sub

	'Required by the Windows Form Designer
	Private components As System.ComponentModel.IContainer

	'NOTE: The following procedure is required by the Windows Form Designer
	'It can be modified using the Windows Form Designer.  
	'Do not modify it using the code editor.
	<System.Diagnostics.DebuggerStepThrough()> _
	Private Sub InitializeComponent()
		components = New System.ComponentModel.Container
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.Text = "ChildTwo"
	End Sub
End Class

Open in new window

ChildThree.vb -
Public Class ChildThree
	Public Property ChildThreeProperty() As String

	Public Sub New()

		' This call is required by the designer.
		InitializeComponent()

		' Add any initialization after the InitializeComponent() call.
		ChildThreeProperty = "Child Three"
	End Sub
End Class

Open in new window

ChildThree.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class ChildThree
	Inherits BaseForm

	'Form overrides dispose to clean up the component list.
	<System.Diagnostics.DebuggerNonUserCode()> _
	Protected Overrides Sub Dispose(ByVal disposing As Boolean)
		Try
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
		Finally
			MyBase.Dispose(disposing)
		End Try
	End Sub

	'Required by the Windows Form Designer
	Private components As System.ComponentModel.IContainer

	'NOTE: The following procedure is required by the Windows Form Designer
	'It can be modified using the Windows Form Designer.  
	'Do not modify it using the code editor.
	<System.Diagnostics.DebuggerStepThrough()> _
	Private Sub InitializeComponent()
		components = New System.ComponentModel.Container
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.Text = "ChildThree"
	End Sub
End Class

Open in new window

ChildFour.vb -
Public Class ChildFour
	Public Property ChildFourProperty() As String

	Public Sub New()

		' This call is required by the designer.
		InitializeComponent()

		' Add any initialization after the InitializeComponent() call.
		ChildFourProperty = "Child Four"
	End Sub
End Class

Open in new window

ChildFour.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class ChildFour
	Inherits BaseForm

	'Form overrides dispose to clean up the component list.
	<System.Diagnostics.DebuggerNonUserCode()> _
	Protected Overrides Sub Dispose(ByVal disposing As Boolean)
		Try
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
		Finally
			MyBase.Dispose(disposing)
		End Try
	End Sub

	'Required by the Windows Form Designer
	Private components As System.ComponentModel.IContainer

	'NOTE: The following procedure is required by the Windows Form Designer
	'It can be modified using the Windows Form Designer.  
	'Do not modify it using the code editor.
	<System.Diagnostics.DebuggerStepThrough()> _
	Private Sub InitializeComponent()
		components = New System.ComponentModel.Container
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.Text = "ChildFour"
	End Sub
End Class

Open in new window

Which produces the following output -Initial load.Pressing button 1 loads an instance of the ChildOne form.  The base form has set it's title window to show this.Understand that this is really a round about way of doing this specific task (setting the Title bar).  From each child I could have easily just set the Text property directly in the constructor:
Public Sub New()

	' This call is required by the designer.
	InitializeComponent()

	' Add any initialization after the InitializeComponent() call.
	Text = "Child One"
End Sub

Open in new window

Or by changing the value in the InitializeComponent method of the Designer file
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.  
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
	components = New System.ComponentModel.Container
	Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
	Me.Text = "Child One"
End Sub

Open in new window

-saige-
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Richie MaddenOwner-OperatorAuthor Commented:
Thanks for the fast response! I won't be able to study it closer until the early morning hours tomorrow when I am in front of my computer. I will followup with any questions, .. so far my question is, this should work with public variables of each child form just like with the property you used?

I think part of my hangup is I have been trying to avoid writing the if / elseif / elseif /... up to 60 times for every sub/function that needs to test for this. I may have no way around that. I can't satisfy the compiler returning the childform inside the declared baseform when the controls don't live in the baseform.

I will followup and mark as accepted solution for sure. Thanks again!
0
käµfm³d 👽Commented:
I wish I could have a conditional right-side assignment...
You can. It's called the If operator (alternatively the Iif function--there is a functional difference between the two). However, I think that's going to be counterproductive in your case. I'm still reading your question, but as a quick example:

Dim leftHand As Accessory = If(isRaining, new Umbrella(), Nothing)

Open in new window

0
Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

Richie MaddenOwner-OperatorAuthor Commented:
Thanks kaufmed... yeah, know this, .... my "want" in your example is to be able to condition Accessory. :)

But, as I am learning abstract class, I am realizing that I can leave Accessory as my abstract class and then use the assignment on a very long if/elseif or select case... trying to create a function for reuse, I have to play with it more when back to my office.

Thanks!
0
käµfm³d 👽Commented:
OK, first, I wouldn't suggest ever doing this:

f.txtFirstName.Text = ""

Code outside of the form itself should not know about the individual controls that you have placed on the form. Doing so introduces a dependency on that specific form. Dependencies are susceptible to errors when things change. You want to try and minimize dependencies in order to reduce errors when things change. You should treat controls as if they are implementation details, and implementation details never break code outside of the class itself (if you're doing things correctly). If it were me, I'd expose a property on the form that is defined by an interface. That property can return the textbox's data, and it can assign to it as well. Your interface property only defines the contract--the form is free to choose how it satisfies that contract.

e.g.

Interface Definition
Public Interface IFirstName
    Property FirstName As String
End Interface

Open in new window


Form Definition
Public Class Form1
    Implements IFirstName


    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Test(Me)    ' You implied in your comments that the form would call Test, so if that's correct, then just pass the form's own instance via Me
    End Sub

    Public Property FirstName As String Implements IFirstName.FirstName
        Get
            Return Me.txtFirstName.Text
        End Get
        Set(value As String)
            Me.txtFirstName.Text = value
        End Set
    End Property
End Class

Open in new window


Test Function Re-definition (Using a module here only for convenience for my development)
Module Module1
    Public Sub Test(ByVal form As IFirstName)

        form.FirstName = String.Empty

    End Sub
End Module

Open in new window


Must you use an interface? No, you can use an abstract class if you like. Both approaches are abstractions. An abstract class will limit your inheritance options, but it would still work.
0
AndyAinscowFreelance programmer / ConsultantCommented:
I think this is correct (and may be relevant).
A major difference between an interface and a class as a base is that a class can only inherit from one class but can inherit from one or many interfaces.
That means you can design numbers of interfaces each with things that belong together and base your new class on only those interfaces it requires.
0
Richie MaddenOwner-OperatorAuthor Commented:
it_saige,

Thank you. And thanks others for your advice and comments.

Unfortunately I am under a strict deadline so do not have the time to rebuild the entire application. Once I have it working, even with some ugly or not the best coding methods, I can then take portions apart at a time and fix. For now, "it is what it is," is how the company looks at this.

Your help will be the accepted solution but I do have one question. I understand by the below code I will not know until run-time if (when) there is a problem.

Here again is a skimmed down version of my situation. Currently this is in a module but saw that you put your Sub in the Abstract form, I guess I will try to move it to the Abstract form and then limit the Abstract form to just the forms that would depend on this method. This will help me organize the forms into collections, as there is no documentation on this application and I'm constantly in the Object Browser to find what forms share control names, methods, and/or functions.

Something else to know, in my situation in why I feel trapped to continue writing shared subs/functions which reference controls is, this sub below, any one of these forms can open "children" of each other. For example, frm1 can create/reference frm2, and then frm2 can create/reference another frm1. All three of these forms have txtName.

If you believe this should work, regardless of how unethical it is to agree with me, I will have to go down this path until I have more time to redo.

Public Sub SetName(ByRef frm As f_AbstractForm, sName as String)

	Dim f As Object      'can be frm1, frm2, frm3
        
        If frm.Name = "frm1" Then
            f = DirectCast(f, frm1)
        ElseIf frm.Name = "frm2" Then
            f = DirectCast(f, frm2)
        ElseIf frm.Name = "frm3" Then
            f = DirectCast(f, frm3)
        End If

        f.txtName.Text = sName

        Set f = Nothing

End Sub

Open in new window

0
it_saigeDeveloperCommented:
First, I chose to implement the code in the abstract form but could have easily implemented it in a module.  But before I do this, you seem to be missing the largest benefit of using an abstract or base form.

While it is all good and well for the forms to use the same code, the benefit of using base forms is that they can also use the same controls.  If you have a common control among your forms, you should implement the control on the base form.  This way all children have access to the common control and you do not have to cast anything.  Consider the following:

BaseForm.vb -
Public Class BaseForm

End Class

Open in new window

BaseForm.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class BaseForm
	Inherits System.Windows.Forms.Form

	'Form overrides dispose to clean up the component list.
	<System.Diagnostics.DebuggerNonUserCode()> _
	Protected Overrides Sub Dispose(ByVal disposing As Boolean)
		Try
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
		Finally
			MyBase.Dispose(disposing)
		End Try
	End Sub

	'Required by the Windows Form Designer
	Private components As System.ComponentModel.IContainer

	'NOTE: The following procedure is required by the Windows Form Designer
	'It can be modified using the Windows Form Designer.  
	'Do not modify it using the code editor.
	<System.Diagnostics.DebuggerStepThrough()> _
	Private Sub InitializeComponent()
		Me.Label1 = New System.Windows.Forms.Label()
		Me.TextBox1 = New System.Windows.Forms.TextBox()
		Me.SuspendLayout()
		'
		'Label1
		'
		Me.Label1.AutoSize = True
		Me.Label1.Location = New System.Drawing.Point(13, 13)
		Me.Label1.Name = "Label1"
		Me.Label1.Size = New System.Drawing.Size(114, 13)
		Me.Label1.TabIndex = 0
		Me.Label1.Text = "Which Child Instance?"
		'
		'TextBox1
		'
		Me.TextBox1.Location = New System.Drawing.Point(133, 10)
		Me.TextBox1.Name = "TextBox1"
		Me.TextBox1.ReadOnly = True
		Me.TextBox1.Size = New System.Drawing.Size(139, 20)
		Me.TextBox1.TabIndex = 1
		'
		'BaseForm
		'
		Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.ClientSize = New System.Drawing.Size(284, 262)
		Me.Controls.Add(Me.TextBox1)
		Me.Controls.Add(Me.Label1)
		Me.Name = "BaseForm"
		Me.Text = "BaseForm"
		Me.ResumeLayout(False)
		Me.PerformLayout()

	End Sub
	Friend WithEvents Label1 As System.Windows.Forms.Label
	Friend WithEvents TextBox1 As System.Windows.Forms.TextBox

End Class

Open in new window

ChildOne.vb -
Public Class ChildOne
	Public Sub New()

		' This call is required by the designer.
		InitializeComponent()

		' Add any initialization after the InitializeComponent() call.
		TextBox1.Text = "Child One"
	End Sub
End Class

Open in new window

ChildOne.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class ChildOne
	Inherits BaseForm

	'Form overrides dispose to clean up the component list.
	<System.Diagnostics.DebuggerNonUserCode()> _
	Protected Overrides Sub Dispose(ByVal disposing As Boolean)
		Try
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
		Finally
			MyBase.Dispose(disposing)
		End Try
	End Sub

	'Required by the Windows Form Designer
	Private components As System.ComponentModel.IContainer

	'NOTE: The following procedure is required by the Windows Form Designer
	'It can be modified using the Windows Form Designer.  
	'Do not modify it using the code editor.
	<System.Diagnostics.DebuggerStepThrough()> _
	Private Sub InitializeComponent()
		components = New System.ComponentModel.Container
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.Text = "ChildOne"
	End Sub
End Class

Open in new window

ChildTwo.vb -
Public Class ChildTwo
	Public Sub New()

		' This call is required by the designer.
		InitializeComponent()

		' Add any initialization after the InitializeComponent() call.
		TextBox1.Text = "Child Two"
	End Sub
End Class

Open in new window

ChildTwo.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class ChildTwo
	Inherits BaseForm

	'Form overrides dispose to clean up the component list.
	<System.Diagnostics.DebuggerNonUserCode()> _
	Protected Overrides Sub Dispose(ByVal disposing As Boolean)
		Try
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
		Finally
			MyBase.Dispose(disposing)
		End Try
	End Sub

	'Required by the Windows Form Designer
	Private components As System.ComponentModel.IContainer

	'NOTE: The following procedure is required by the Windows Form Designer
	'It can be modified using the Windows Form Designer.  
	'Do not modify it using the code editor.
	<System.Diagnostics.DebuggerStepThrough()> _
	Private Sub InitializeComponent()
		components = New System.ComponentModel.Container
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.Text = "ChildTwo"
	End Sub
End Class

Open in new window

ChildThree.vb -
Public Class ChildThree
	Public Sub New()

		' This call is required by the designer.
		InitializeComponent()

		' Add any initialization after the InitializeComponent() call.
		TextBox1.Text = "Child Three"
	End Sub
End Class

Open in new window

ChildThree.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class ChildThree
	Inherits BaseForm

	'Form overrides dispose to clean up the component list.
	<System.Diagnostics.DebuggerNonUserCode()> _
	Protected Overrides Sub Dispose(ByVal disposing As Boolean)
		Try
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
		Finally
			MyBase.Dispose(disposing)
		End Try
	End Sub

	'Required by the Windows Form Designer
	Private components As System.ComponentModel.IContainer

	'NOTE: The following procedure is required by the Windows Form Designer
	'It can be modified using the Windows Form Designer.  
	'Do not modify it using the code editor.
	<System.Diagnostics.DebuggerStepThrough()> _
	Private Sub InitializeComponent()
		components = New System.ComponentModel.Container
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.Text = "ChildThree"
	End Sub
End Class

Open in new window

ChildFour.vb -
Public Class ChildFour
	Public Sub New()

		' This call is required by the designer.
		InitializeComponent()

		' Add any initialization after the InitializeComponent() call.
		TextBox1.Text = "Child Four"
	End Sub
End Class

Open in new window

ChildFour.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class ChildFour
	Inherits BaseForm

	'Form overrides dispose to clean up the component list.
	<System.Diagnostics.DebuggerNonUserCode()> _
	Protected Overrides Sub Dispose(ByVal disposing As Boolean)
		Try
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
		Finally
			MyBase.Dispose(disposing)
		End Try
	End Sub

	'Required by the Windows Form Designer
	Private components As System.ComponentModel.IContainer

	'NOTE: The following procedure is required by the Windows Form Designer
	'It can be modified using the Windows Form Designer.  
	'Do not modify it using the code editor.
	<System.Diagnostics.DebuggerStepThrough()> _
	Private Sub InitializeComponent()
		components = New System.ComponentModel.Container
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.Text = "ChildFour"
	End Sub
End Class

Open in new window

MainForm.vb -
Public Class MainForm
	Private Sub OnClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click, Button3.Click, Button2.Click, Button1.Click
		If TypeOf sender Is Button Then
			Dim btn = DirectCast(sender, Button)
			Dim form As New BaseForm
			If btn.Equals(Button1) Then
				form = New ChildOne()
				form.Show()
			ElseIf btn.Equals(Button2) Then
				form = New ChildTwo()
				form.Show()
			ElseIf btn.Equals(Button3) Then
				form = New ChildThree()
				form.Show()
			ElseIf btn.Equals(Button4) Then
				form = New ChildFour()
				form.Show()
			End If
		End If
	End Sub
End Class

Open in new window

MainForm.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class MainForm
	Inherits System.Windows.Forms.Form

	'Form overrides dispose to clean up the component list.
	<System.Diagnostics.DebuggerNonUserCode()> _
	Protected Overrides Sub Dispose(ByVal disposing As Boolean)
		Try
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
		Finally
			MyBase.Dispose(disposing)
		End Try
	End Sub

	'Required by the Windows Form Designer
	Private components As System.ComponentModel.IContainer

	'NOTE: The following procedure is required by the Windows Form Designer
	'It can be modified using the Windows Form Designer.  
	'Do not modify it using the code editor.
	<System.Diagnostics.DebuggerStepThrough()> _
	Private Sub InitializeComponent()
		Me.Button1 = New System.Windows.Forms.Button()
		Me.Button2 = New System.Windows.Forms.Button()
		Me.Button3 = New System.Windows.Forms.Button()
		Me.Button4 = New System.Windows.Forms.Button()
		Me.SuspendLayout()
		'
		'Button1
		'
		Me.Button1.Location = New System.Drawing.Point(13, 13)
		Me.Button1.Name = "Button1"
		Me.Button1.Size = New System.Drawing.Size(75, 23)
		Me.Button1.TabIndex = 0
		Me.Button1.Text = "Button1"
		Me.Button1.UseVisualStyleBackColor = True
		'
		'Button2
		'
		Me.Button2.Location = New System.Drawing.Point(13, 43)
		Me.Button2.Name = "Button2"
		Me.Button2.Size = New System.Drawing.Size(75, 23)
		Me.Button2.TabIndex = 1
		Me.Button2.Text = "Button2"
		Me.Button2.UseVisualStyleBackColor = True
		'
		'Button3
		'
		Me.Button3.Location = New System.Drawing.Point(13, 73)
		Me.Button3.Name = "Button3"
		Me.Button3.Size = New System.Drawing.Size(75, 23)
		Me.Button3.TabIndex = 2
		Me.Button3.Text = "Button3"
		Me.Button3.UseVisualStyleBackColor = True
		'
		'Button4
		'
		Me.Button4.Location = New System.Drawing.Point(13, 103)
		Me.Button4.Name = "Button4"
		Me.Button4.Size = New System.Drawing.Size(75, 23)
		Me.Button4.TabIndex = 3
		Me.Button4.Text = "Button4"
		Me.Button4.UseVisualStyleBackColor = True
		'
		'MainForm
		'
		Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.ClientSize = New System.Drawing.Size(284, 262)
		Me.Controls.Add(Me.Button4)
		Me.Controls.Add(Me.Button3)
		Me.Controls.Add(Me.Button2)
		Me.Controls.Add(Me.Button1)
		Me.Name = "MainForm"
		Me.Text = "MainForm"
		Me.ResumeLayout(False)

	End Sub
	Friend WithEvents Button1 As System.Windows.Forms.Button
	Friend WithEvents Button2 As System.Windows.Forms.Button
	Friend WithEvents Button3 As System.Windows.Forms.Button
	Friend WithEvents Button4 As System.Windows.Forms.Button
End Class

Open in new window

Which now produces the following output -Initial load.Pressing the button to spawn a child one instance and viola, child one has updated the control on the base form to reflect the text.  All without specifying a single cast.
-saige-
0
it_saigeDeveloperCommented:
This still follows the pattern that Kaufmed pointed out as well.  While the BaseForm contains the initial definition of the object (the contract if you will), the child form controls the implementation details of the object.  Understand, however, that this implementation is optional.

Let's make a quick change to the BaseForm:
BaseForm.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class BaseForm
	Inherits System.Windows.Forms.Form

	'Form overrides dispose to clean up the component list.
	<System.Diagnostics.DebuggerNonUserCode()> _
	Protected Overrides Sub Dispose(ByVal disposing As Boolean)
		Try
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
		Finally
			MyBase.Dispose(disposing)
		End Try
	End Sub

	'Required by the Windows Form Designer
	Private components As System.ComponentModel.IContainer

	'NOTE: The following procedure is required by the Windows Form Designer
	'It can be modified using the Windows Form Designer.  
	'Do not modify it using the code editor.
	<System.Diagnostics.DebuggerStepThrough()> _
	Private Sub InitializeComponent()
		Me.Label1 = New System.Windows.Forms.Label()
		Me.TextBox1 = New System.Windows.Forms.TextBox()
		Me.SuspendLayout()
		'
		'Label1
		'
		Me.Label1.AutoSize = True
		Me.Label1.Location = New System.Drawing.Point(13, 13)
		Me.Label1.Name = "Label1"
		Me.Label1.Size = New System.Drawing.Size(114, 13)
		Me.Label1.TabIndex = 0
		Me.Label1.Text = "Which Child Instance?"
		'
		'TextBox1
		'
		Me.TextBox1.Location = New System.Drawing.Point(133, 10)
		Me.TextBox1.Name = "TextBox1"
		Me.TextBox1.ReadOnly = True
		Me.TextBox1.Size = New System.Drawing.Size(139, 20)
		Me.TextBox1.TabIndex = 1
		Me.TextBox1.Text = "My child has abandoned me"
		'
		'BaseForm
		'
		Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.ClientSize = New System.Drawing.Size(284, 262)
		Me.Controls.Add(Me.TextBox1)
		Me.Controls.Add(Me.Label1)
		Me.Name = "BaseForm"
		Me.Text = "BaseForm"
		Me.ResumeLayout(False)
		Me.PerformLayout()

	End Sub
	Friend WithEvents Label1 As System.Windows.Forms.Label
	Friend WithEvents TextBox1 As System.Windows.Forms.TextBox

End Class

Open in new window

And now lets modify ChildFour:
ChildFour.vb -
Public Class ChildFour
	Public Sub New()

		' This call is required by the designer.
		InitializeComponent()

		' Add any initialization after the InitializeComponent() call.
		' We are going to abandon the control on the base form by chosing not to change the implementation (contract) details
		' TextBox1.Text = "Child Four"
	End Sub
End Class

Open in new window

Now lets rerun our application and see what happens when we spawn ChildFour -Capture.JPG-saige-
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.