Home > Software design >  Send data within Child Forms
Send data within Child Forms

Time:10-28

I have 3 Forms namely MainForm, Form1 and Form2. MainForm hosts Form1 in a Panel. On Clicking a button in MainForm, I am opening Form2 using ShowDialog() method. Now I have a treeview in Form2. Now I want to pass the nodes selected in Form2 back to a combobox in Form1. How can this be achieved? I have tried Form1.Activate() in Form2 but the code is not hitting Activate method in Form1.

Also I am using Form1.ComboBox1.Items.Add(Me.TreeView1.SelectedNode.Text) but I cannot see any items in ComboBox once Form2 is closed. What am I missing here?

Below is the code for better understanding.

MainForm

public Class MainForm

   private Sub OpenChildForm(childForm As Form)
       panelFormContainer.Controls.Add(childForm)
       childForm.Dock = DockStyle.Fill
       childForm.Show()
   End Sub  
   
   private sub MainForm_OnLoad(sender As Object, e as EventArgs) Handles Me.Load
      
      'Adding child form to a Panel in Main Form
      OpenChildForm(new Form1())
   End Sub

   'Open Form 2 on Button Click
   private sub btnOpenForm3_Click(sender As Object, e as EventArgs) Handles btnOpenForm3.Click
       Form2.ShowDialog()
   End Sub 
End Class   

Form2 - Child Form Opened by button click in MainForm

Public Class Form2

   'Click back button to go back to Main Form which is already having Form1 as child
   Private Sub btnBack_Click(sender As Object, e As EventArgs)
      Me.Close()
      Form1.Activate()
   End Sub

   'Click a Button to Add Selected Treeview node to Combo in Form1 
   Private Sub btnAdd_Click(sender As Object, e As EventArgs) btnAdd.Click
      Form1.ComboBox1.Items.Add(Me.TreeView1.SelectedNode.Text)
   End Sub

End Class

Updated: I have updated the code but still not getting anything in ComboBox of Child Form1

MainForm

Public Class Form1

Private currentChildForm As Form = Nothing
Private ownerForm As Form = Nothing
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    OpenChildForm(New ChildForm1())

End Sub

Private Sub OpenChildForm(childForm As Form)
    If currentChildForm IsNot Nothing Then
        currentChildForm.Close()
    End If

    childForm.TopLevel = False
    childForm.FormBorderStyle = FormBorderStyle.None
    panelFormContainer.Controls.Clear()

    panelFormContainer.Controls.Add(childForm)

    childForm.Dock = DockStyle.Fill

    childForm.BringToFront()
    childForm.Show()

End Sub

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim dialogForm As ChildForm2 = New ChildForm2()
    '
    Dim result = dialogForm.ShowDialog()
    If result = DialogResult.OK Then
        AddHandler ChildForm2.Button1.Click, AddressOf ChildForm1.objForm2_Passvalue
    End If
End Sub


End Class

ChildForm1 which is hosted in MainForm

Public Class ChildForm1
    Private Sub ChildForm1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    If ComboBox1.Items.Count > 0 Then
        ComboBox1.SelectedIndex = 0
    End If
End Sub

Private Sub ChildForm1_Activated(sender As Object, e As EventArgs) Handles Me.Activated

End Sub

Public Sub objForm2_Passvalue(sender As Object, e As EventArgs)
    Me.ComboBox1.Items.Add(PageDetail.PageTitle)
End Sub

End Class

ChildForm2 -- Which is opened as Dialog

Public Class ChildForm2

Private Sub ChildForm2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    TreeView1.ExpandAll()
    Button1.DialogResult = DialogResult.OK
End Sub

Public Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    PageDetail.PageTitle = TreeView1.SelectedNode.Text
    Me.Close()
End Sub

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    Me.Close()
End Sub
End Class

PageDetail: Class used to get and set data

Public NotInheritable Class PageDetail

    Private Shared pageTitleValue As String

    Public Shared Property PageTitle As String
        Get
            Return pageTitleValue
        End Get
        Set(value As String)
            pageTitleValue = value
        End Set
    End Property

End Class

Child Forms Demo

CodePudding user response:

Rather than placing a Form on a panel, you might consider creating a UserControl and placing that on the panel. The following show how to pass data from a Form (Form2) that is shown using ShowDialog() to a UserControl (UserControl1) that exists on a different form (MainForm).

Note: MainForm is the startup form. If desired, the UserControl can be replaced with a Form.

Create a new project

VS 2019:

  • In VS menu, click File

  • Select New

  • Select Project

  • enter image description here

  • Select Windows Forms App (.NET Framework)

    enter image description here

  • Click Next

  • Enter desired project name

  • Click Create


Open Solution Explorer

  • In VS menu, select View
  • Select Solution Explorer

Add UserControl (Name: UserControl1.vb)

  • In Solution Explorer, right-click <project name>, select Add

  • Select User Control (Windows Forms)... (name: UserControl1.vb)

  • Add a Label (Text: "Select One")

  • Add a ComboBox (Name: ComboBox1)

    enter image description here

UserControl1.vb

Public Class UserControl1

    Private Sub UserControl1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    End Sub

    Public Sub PopulateComboBox(value As String)
        'remove existing data from ComboBox
        ComboBox1.Items.Clear()
        ComboBox1.Text = String.Empty

        'add 
        ComboBox1.Items.Add(value)

        If ComboBox1.Items.Count = 1 Then
            'if only 1 item exists, select it
            ComboBox1.SelectedIndex = 0
        End If
    End Sub
End Class

Note: If using a Form instead of a UserControl, add the code for PopulateComboBox to your form.


Add a Form (name: Form2.vb)

  • In Solution Explorer, right-click <project name>, select Add

  • Select Form (Windows Forms)... (Name: Form2.vb)

  • Add a Label

  • Add a TreeView (name: TreeView1)

  • Add a Button (Name: btnAdd; Text: Add)

  • Double-click "btnAdd" to add the Click event handler

  • Add a Button (Name: btnCancel; Text: Cancel)

  • Double-click "btnCancel" to add the Click event handler

    enter image description here

In Solution Explorer, right click Form2.vb, and select View Code

Form2.vb

Imports System.IO
Public Class Form2

    Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        PopulateTreeView()
    End Sub

    'ToDo: Replace this function with one that returns the desired data
    Public Function GetSelectedValue() As String
        Return TreeView1.SelectedNode.Text
    End Function

    Private Sub PopulateTreeView()

        'ToDo: Replace this code with your desired code to populate the TreeView

        'clear
        TreeView1.Nodes.Clear()

        Dim topNode As TreeNode = New TreeNode("Computer")

        TreeView1.Nodes.Add(topNode)

        Dim logicalDrives As String() = Directory.GetLogicalDrives()

        If logicalDrives IsNot Nothing Then
            For Each drive As String In logicalDrives
                Debug.WriteLine("drive: " & drive.ToString())

                Try
                    Dim dirInfo As DirectoryInfo = New DirectoryInfo(drive)

                    TreeView1.Nodes.Add(New TreeNode(drive))

                Catch ex As Exception
                    'do nothing
                End Try
            Next
        End If
    End Sub

    Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
        'in MainForm we'll subscribe to the Add button Click event and retrieve the data by calling function "GetSelectedValue", so all we have to do here is close the form
        Me.Close()
    End Sub

    Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
        Me.Close()
    End Sub
End Class

Rename Form1 to MainForm

  • In Solution Explorer, right-click Form1.vb
  • Select Rename
  • Enter MainForm.vb
  • When prompted "You are renaming a file. Would you also like to perform a rename in this project of all references to the code element 'Form1'? Click Yes
  • In Properties Window, for "MainForm", set Text = "MainForm"

Build Project

  • In Solution Explorer, right-click <project name>, select Build

MainForm

  • Add a panel to MainForm (Name: panel1)

  • In Toolbox (View => Toolbox), expand: <solution name> Components

  • Drag UserControl1 onto panel1 on MainForm

  • Add Button (Name: btnOpenForm2; Text: Open Form2)

  • Double-click "btnOpenForm2" to add the Click event handler

    enter image description here

In Solution Explorer, right click MainForm.vb, and select View Code

MainForm.vb

Public Class MainForm

    Private frm2 As Form2 = Nothing

    Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    End Sub

    Private Sub btnOpenForm2_Click(sender As Object, e As EventArgs) Handles btnOpenForm2.Click
        If frm2 Is Nothing Then
            'create new instance
            frm2 = New Form2()
        End If

        'subscribe to events (add event handlers)
        AddHandler frm2.btnAdd.Click, AddressOf Frm2BtnAdd_Click

        'show dialog 
        frm2.ShowDialog()

        'the code below will execute after frm2 is closed

        'unsubscribe from events (remove event handlers)
        RemoveHandler frm2.btnAdd.Click, AddressOf Frm2BtnAdd_Click

        'dispose
        frm2.Dispose()

        frm2 = Nothing
    End Sub

    Private Sub Frm2BtnAdd_Click(sender As Object, e As System.EventArgs)

        'call method to populate ComboBox
        'UserControl11.PopulateComboBox(frm2.GetSelectedValue())

        'call function to get data
        Dim userSelection As String = frm2.GetSelectedValue()

        'call method to populate ComboBox
        UserControl11.PopulateComboBox(userSelection)

    End Sub
End Class

Here's a demonstration:

enter image description here

Resources

  • enter image description here

    Note: MainForm is the startup form and is the parent to both ChildForm1 and ChildForm2 (ie: instances of both ChildForm1 and ChildForm2 are created in MainForm)

    Create a new project

    VS 2019:

    • In VS menu, click File
    • Select New
    • Select Project
    • enter image description here
    • Select Windows Forms App (.NET Framework)

    enter image description here

    • Click Next
    • Enter desired project name
    • Click Create

    Open Solution Explorer

    • In VS menu, select View
    • Select Solution Explorer

    Add Form (Name: ChildForm1.vb)

    • In Solution Explorer, right-click <project name>, select Add
    • Select Form (Windows Forms)... (name: ChildForm1.vb)
    • Add a Label (Text: "Select One")
    • Add a ComboBox (Name: ComboBox1)

    enter image description here

    In Solution Explorer, right click ChildForm1.vb, and select View Code

    ChildForm1.vb

    Public Class ChildForm1
    
        Public WriteOnly Property PageTitle As String
            Set(value As String)
                'populate ComboBox
                PopulateComboBox(value)
            End Set
        End Property
    
        Sub New()
    
            ' This call is required by the designer.
            InitializeComponent()
    
            ' Add any initialization after the InitializeComponent() call.
    
        End Sub
    
        Sub New(pageTitle As String)
    
            ' This call is required by the designer.
            InitializeComponent()
    
            ' Add any initialization after the InitializeComponent() call.
            PopulateComboBox(pageTitle)
    
        End Sub
    
        Sub New(pageTitles As List(Of String))
    
            ' This call is required by the designer.
            InitializeComponent()
    
            ' Add any initialization after the InitializeComponent() call.
            PopulateComboBox(pageTitles)
    
        End Sub
    
        Private Sub ChildForm1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
        End Sub
    
        Public Sub PopulateComboBox(pageTitle As String)
            'create new instance
            Dim pageTitles As New List(Of String)
    
            'add
            pageTitles.Add(pageTitle)
    
            'populate ComboBox
            PopulateComboBox(pageTitles)
        End Sub
    
        Public Sub PopulateComboBox(pageTitles As List(Of String))
            'remove existing data from ComboBox
            ComboBox1.Items.Clear()
            ComboBox1.Text = String.Empty
    
            For Each pTitle In pageTitles
                'add 
                ComboBox1.Items.Add(pTitle)
            Next
    
            If ComboBox1.Items.Count = 1 Then
                'if only 1 item exists, select it
                ComboBox1.SelectedIndex = 0
            End If
        End Sub
    End Class
    

    Add a Form (name: ChildForm2.vb)

    • In Solution Explorer, right-click <project name>, select Add
    • Select Form (Windows Forms)... (Name: ChildForm2.vb)
    • Add a Label
    • Add a TreeView (name: TreeView1)
    • Add a Button (Name: btnAdd; Text: Add)
    • Double-click "btnAdd" to add the Click event handler
    • Add a Button (Name: btnCancel; Text: Cancel)
    • Double-click "btnCancel" to add the Click event handler

    enter image description here

    In Solution Explorer, right click ChildForm2.vb, and select View Code

    ChildForm2.vb

    Public Delegate Sub PassValueHandler(ByVal strValue As String)
    
    Public Class ChildForm2
    
        Public Event PassValue As PassValueHandler
    
        Public ReadOnly Property PageTitle
            Get
                Return TreeView1.SelectedNode.Text
            End Get
        End Property
    
        Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            PopulateTreeView()
            TreeView1.ExpandAll()
        End Sub
    
        Public Function GetPageTitle() As String
            Return PageTitle
        End Function
    
        Private Sub PopulateTreeView()
            'ToDo: Replace this method with code to populate your TreeView
    
            TreeView1.Nodes.Clear()
    
            'Parent 1
            Dim node1 As TreeNode = New TreeNode("Parent 1")
            Dim childNode1 As TreeNode = New TreeNode("Child Node 1")
    
            'add 
            node1.Nodes.Add(childNode1)
    
            'add 
            TreeView1.Nodes.Add(node1)
    
            'Parent 2
            Dim node2 As TreeNode = New TreeNode("Parent 2")
            Dim childNode2 As TreeNode = New TreeNode("Child Node 2")
    
            'add 
            node2.Nodes.Add(childNode2)
    
            'add 
            TreeView1.Nodes.Add(node2)
    
        End Sub
    
        Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
            'raise event
            RaiseEvent PassValue(TreeView1.SelectedNode.Text)
    
            'set value
            Me.DialogResult = DialogResult.OK
    
            'close
            Me.Close()
    
        End Sub
    
        Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
            'set value
            Me.DialogResult = DialogResult.Cancel
    
            'close
            Me.Close()
        End Sub
    End Class
    

    Rename Form1 to MainForm

    • In Solution Explorer, right-click Form1.vb
    • Select Rename
    • Enter MainForm.vb
    • When prompted "You are renaming a file. Would you also like to perform a rename in this project of all references to the code element 'Form1'? Click Yes
    • In Properties Window, for "MainForm", set Text = "MainForm"

    MainForm

    • Add a panel to MainForm (Name: panelFormContainer)
    • Add Button (Name: btnOpenChildForm2; Text: Open ChildForm2)
    • Double-click "btnOpenChildForm2" to add the Click event handler

    enter image description here

    In Solution Explorer, right click MainForm.vb, and select View Code

    In the code below, I've written it in such a way that it allows one to choose different options for both retrieving data from a child form, as well as, multiple options for sending data to a child form.

    MainForm.vb

    Public Class MainForm
    
        Private dialogForm As ChildForm2 = Nothing
        Private currentChildForm As Form = Nothing
        Private ownerForm As Form = Nothing
    
        Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
            'open Form
            OpenChildForm(New ChildForm1())
        End Sub
    
        Private Sub OpenChildForm(ByRef childForm As Form)
            If currentChildForm IsNot Nothing Then
                currentChildForm.Dispose()
                currentChildForm = Nothing
            End If
    
            'set value
            currentChildForm = childForm
    
            'set properties
            childForm.Dock = DockStyle.Fill
            childForm.TopLevel = False
            childForm.FormBorderStyle = FormBorderStyle.None
    
            'remove existing controls
            panelFormContainer.Controls.Clear()
    
            'add
            panelFormContainer.Controls.Add(childForm)
    
            'show
            childForm.Show()
    
        End Sub
    
        Private Sub PopulateChildForm1ComboBox(pageTitle As String)
            If currentChildForm.GetType() = ChildForm1.GetType() Then
                'currentChildForm is an instance of ChildForm1
    
                'create reference
                Dim frm = CType(currentChildForm, ChildForm1)
    
                'option 1 - populate ComboBox by calling method
                frm.PopulateComboBox(pageTitle)
    
                'option 2 - populate ComboBox by setting property
                'frm.PageTitle = PageDetail.PageTitle
            End If
        End Sub
    
        Private Sub btnOpenChildForm2_Click(sender As Object, e As EventArgs) Handles btnOpenChildForm2.Click
            'ToDo: Replace this method with code from Option 1, Option 2, or Option 3 below
                               ...
    
        End Sub
    
        Private Sub DialogForm_BtnAdd_Click(sender As Object, e As System.EventArgs)
    
            'option 1 - get page title from property
            PageDetail.PageTitle = dialogForm.PageTitle
    
            'option 2 - get page title by calling function
            'PageDetail.PageTitle = dialogForm.GetPageTitle()
    
            'populate ComboBox
            PopulateChildForm1ComboBox(PageDetail.PageTitle)
        End Sub
    
        Private Sub DialogForm_PassValue(e As String)
            'set value
            PageDetail.PageTitle = e
    
            'populate ComboBox
            PopulateChildForm1ComboBox(e)
        End Sub
    End Class
    

    Choose one of the following options for retrieving data from ChildForm2. Replace the method btnOpenChildForm2_Click (in MainForm.vb) with the code listed below.

    Option 1 (DialogResult.OK)

    Private Sub btnOpenChildForm2_Click(sender As Object, e As EventArgs) Handles btnOpenChildForm2.Click
        'create new instance
        dialogForm = New ChildForm2()
    
        'show dialog
        If dialogForm.ShowDialog() = DialogResult.OK Then
            PageDetail.PageTitle = dialogForm.PageTitle
    
            'populate ComboBox
            PopulateChildForm1ComboBox(PageDetail.PageTitle)
        End If
    
        'dispose
        dialogForm.Dispose()
    
        dialogForm = Nothing
    End Sub
    

    Note: When using Option 1, the code for DialogForm_BtnAdd_Click and DialogForm_PassValue (in MainForm.vb) isn't used, so both of these methods can be removed.

    Option 2 (subscribe to btnAdd 'Click' event)

    Private Sub btnOpenChildForm2_Click(sender As Object, e As EventArgs) Handles btnOpenChildForm2.Click
        'create new instance
        dialogForm = New ChildForm2()
    
        'subscribe to events (add event handlers)
        AddHandler dialogForm.btnAdd.Click, AddressOf DialogForm_BtnAdd_Click
    
        'show dialog
        dialogForm.ShowDialog()
    
        'unsubscribe from events (remove event handlers)
        RemoveHandler dialogForm.btnAdd.Click, AddressOf DialogForm_BtnAdd_Click
    
        'dispose
        dialogForm.Dispose()
    
        dialogForm = Nothing
    End Sub
    

    Note: When using Option 2, the code for DialogForm_PassValue (in MainForm.vb) isn't used, so method DialogForm_PassValue can be removed.

    Option 3 (subscribe to event 'PassValue')

    Private Sub btnOpenChildForm2_Click(sender As Object, e As EventArgs) Handles btnOpenChildForm2.Click
        'create new instance
        dialogForm = New ChildForm2()
    
        'subscribe to events (add event handlers)
        AddHandler dialogForm.PassValue, AddressOf DialogForm_PassValue
    
        'show dialog
        dialogForm.ShowDialog()
    
        'unsubscribe from events (remove event handlers)
        RemoveHandler dialogForm.PassValue, AddressOf DialogForm_PassValue
    
        'dispose
        dialogForm.Dispose()
    
        dialogForm = Nothing
    End Sub
    

    Note: When using Option 3, the code for DialogForm_BtnAdd_Click (in MainForm.vb) isn't used, so method DialogForm_BtnAdd_Click can be removed.


    Here's a demo:

    enter image description here

    Resources:

  • Related