【问题标题】:Send data within Child Forms在子表单中发送数据
【发布时间】:2021-10-25 16:23:11
【问题描述】:

我有 3 个表单,即 MainForm、Form1 和 Form2。 MainForm 在 Panel 中托管 Form1。在 MainForm 中单击 button 时,我正在使用 ShowDialog() 方法打开 Form2。现在我在Form2 中有一个treeview现在我想将 Form2 中选择的节点传递回 Form1 中的 combobox。如何做到这一点?我在 Form2 中尝试过 Form1.Activate(),但代码没有在 Form1 中达到 Activate 方法。

我也在使用Form1.ComboBox1.Items.Add(Me.TreeView1.SelectedNode.Text),但是一旦 Form2 关闭,我就看不到 ComboBox 中的任何项目。我在这里错过了什么?

下面是更好理解的代码。

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

更新:我已经更新了代码,但在 Child Form1 的 ComboBox 中仍然没有得到任何东西

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

【问题讨论】:

  • 有很多方法可以做到这一点,最好的方法完全取决于你。由于您执行 Form2.ShowDialog(),您可以简单地更改 TreeView1 上的访问修饰符,以便在 btnOpenForm3_Click 事件中对 MainForm 可见。您可能还想阅读默认表单实例。 Form1 和 Form2,可能不是您要查找的表单的实际实例
  • 什么是PageDetail.PageTitle
  • @user9938:它只是一个具有设置数据属性的类。也将其添加到代码中。
  • 我添加了另一个解决方案,展示了在表单之间传递数据的更多方法。希望其中一个对您有用。

标签: vb.net winforms


【解决方案1】:

以下显示了在表单之间传递数据的多种方式。在下面的代码中,我展示了如何使用函数、属性或事件从子窗体 (ChildForm2) 中检索数据。此数据被传递回父窗体 (MainForm)。一旦父窗体 (MainForm) 接收到数据,它将数据发送到不同的子窗体 (ChildForm1)。可以使用构造函数、方法或属性之一将数据从父窗体 (MainForm) 发送到子窗体 (ChildForm1)。

注意MainForm 是启动窗体,是 ChildForm1ChildForm2 的父窗体(即:ChildForm1ChildForm2 的实例都在 MainForm 中创建)

创建一个新项目

VS 2019

  • 在VS菜单中,点击文件
  • 选择新建
  • 选择项目
  • 选择 Windows 窗体应用程序 (.NET Framework)

  • 点击下一步
  • 输入所需的项目名称
  • 点击创建

打开解决方案资源管理器

  • 在VS菜单中,选择查看
  • 选择解决方案资源管理器

添加表单(名称:ChildForm1.vb)

  • 在解决方案资源管理器中,右键单击,选择添加
  • 选择窗体(Windows 窗体)...(名称:ChildForm1.vb)
  • 添加Label(文本:“选择一个”)
  • 添加ComboBox(名称:ComboBox1)

在解决方案资源管理器中,右键单击ChildForm1.vb,然后选择查看代码

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

添加表单(名称:ChildForm2.vb)

  • 在解决方案资源管理器中,右键单击,选择添加
  • 选择窗体(Windows 窗体)...(名称:ChildForm2.vb)
  • 添加标签
  • 添加一个TreeView(名称:TreeView1)
  • 添加一个按钮(名称:btnAdd;文本:Add)
  • 双击“btnAdd”以添加 Click 事件处理程序
  • 添加一个按钮(名称:btnCancel;文本:Cancel)
  • 双击“btnCancel”以添加 Click 事件处理程序

在解决方案资源管理器中,右键单击ChildForm2.vb,然后选择查看代码

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

将 Form1 重命名为 MainForm

  • 在解决方案资源管理器中,右键单击 Form1.vb
  • 选择重命名
  • 输入 MainForm.vb
  • 当提示“您正在重命名文件。您还想在此项目中对代码元素“Form1”的所有引用执行重命名吗?单击
  • 在“属性”窗口中,为“MainForm”设置 Text = “MainForm”

主窗体

  • 向 MainForm 添加面板(名称:panelFormContainer)
  • 添加按钮(名称:btnOpenChildForm2;文本:Open ChildForm2)
  • 双击“btnOpenChildForm2”以添加 Click 事件处理程序

在解决方案资源管理器中,右键单击MainForm.vb,然后选择查看代码

在下面的代码中,我以这样一种方式编写了它,它允许人们选择不同的选项来从子表单中检索数据,以及将数据发送到子表单的多个选项。

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

选择以下选项之一从 ChildForm2 中检索数据。将方法 btnOpenChildForm2_Click(在 MainForm.vb 中)替换为下面列出的代码。

选项 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

注意:使用Option 1时,DialogForm_BtnAdd_ClickDialogForm_PassValue的代码(在MainForm.vb中)没有使用,所以这两个方法都可以去掉。

选项 2(订阅 btnAdd 'Click' 事件)

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

注意:使用Option 2时,不使用DialogForm_PassValue(在MainForm.vb中)的代码,因此可以删除方法DialogForm_PassValue

选项 3(订阅事件“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

注意:使用Option 3时,不使用DialogForm_BtnAdd_Click(在MainForm.vb中)的代码,因此可以删除方法DialogForm_BtnAdd_Click


这是一个演示

资源

【讨论】:

  • 不知道我之前犯了什么错误。所有 3 个选项都运行良好。非常感谢。可能是使用CType 投射表单成功了。
【解决方案2】:

与其将Form 放置在面板上,不如考虑创建UserControl 并将其放置在面板上。下面展示了如何将数据从使用ShowDialog() 显示的表单 (Form2) 传递到存在于不同表单 (MainForm) 上的用户控件 (UserControl1)。

注意MainForm是启动表单。如果需要,可以将 UserControl 替换为 Form。

创建一个新项目

VS 2019

  • 在VS菜单中,点击文件

  • 选择新建

  • 选择项目

  • 选择Windows 窗体应用程序(.NET 框架)

  • 点击下一步

  • 输入所需的项目名称

  • 点击创建


打开解决方案资源管理器

  • 在VS菜单中,选择查看
  • 选择解决方案资源管理器

添加用户控件(名称:UserControl1.vb)

  • 在解决方案资源管理器中,右键单击,选择添加

  • 选择用户控件(Windows 窗体)...(名称:UserControl1.vb)

  • 添加Label(文本:“选择一个”)

  • 添加ComboBox(名称:ComboBox1)

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

注意:如果使用Form 而不是UserControl,请将PopulateComboBox 的代码添加到您的表单中。


添加表单(名称:Form2.vb)

  • 在解决方案资源管理器中,右键单击,选择添加

  • 选择窗体(Windows 窗体)...(名称:Form2.vb)

  • 添加标签

  • 添加一个TreeView(名称:TreeView1)

  • 添加一个按钮(名称:btnAdd;文本:Add)

  • 双击“btnAdd”以添加 Click 事件处理程序

  • 添加一个按钮(名称:btnCancel;文本:Cancel)

  • 双击“btnCancel”以添加 Click 事件处理程序

在解决方案资源管理器中,右键单击Form2.vb,然后选择查看代码

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

将 Form1 重命名为 MainForm

  • 在解决方案资源管理器中,右键单击 Form1.vb
  • 选择重命名
  • 输入 MainForm.vb
  • 当提示“您正在重命名文件。您还想在此项目中对代码元素“Form1”的所有引用执行重命名吗?单击
  • 在“属性”窗口中,为“MainForm”设置 Text = “MainForm”

构建项目

  • 在解决方案资源管理器中,右键单击,选择构建

主窗体

  • 向 MainForm 添加面板(名称:panel1)

  • 在工具箱(视图 => 工具箱)中,展开: 组件

  • UserControl1拖到MainForm上的panel1

  • 添加按钮(名称:btnOpenForm2;文本:Open Form2)

  • 双击“btnOpenForm2”以添加 Click 事件处理程序

在解决方案资源管理器中,右键单击MainForm.vb,然后选择查看代码

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

这是一个演示

资源

【讨论】:

  • 感谢您的详细回答,但我的要求是,我的组合框不在“MainForm”中,而是在 MainForm 中的另一个窗体中。在这个表单中,除了组合框之外,我还有一些其他控件。我正在从 MainForm 打开 Form2,但我想在 Form2 关闭后在 Form1 中填充组合。如何做到这一点?我应该在放置 Combo 的表单中使用“AddHandler”和“RemoveHandler”吗?
  • 上述代码中的ComboBox 不在MainForm 中-它在UserControl1 中(您可以在其中添加其他控件。如果需要,在上述代码中替换@987654349 @ 和相关的代码,用Form1。我建议你创建一个新项目并按照上面的步骤一步一步来,而不是仅仅尝试阅读它。
  • 是的,我正在尝试您的示例。它适用于 Usercontrol,但不适用于 Form。我有一个带有 Combo 的表单以及许多其他控件。如何让它与 Form 一起工作?
  • 我好像忘记发布“UserControl1.vb”的代码了——我已经把它添加到帖子中了。
  • Frm2BtnAdd_Click (MainForm.vb) 中,我将语句拆分以使其更易于理解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-01
  • 2017-08-27
  • 2020-04-22
  • 1970-01-01
相关资源
最近更新 更多