如何从另一个模式对话框窗体向MDI子窗体传递多个信息

时间:2014-10-28 17:58:15

标签: vb.net vb.net-2010

我尝试使用委托将信息从对话框表单传递到活动的MDI子表单(不是父表单),但它只接受一个数据,如何使用多个数据执行此操作,如下图所示:

这是我到目前为止使用的:它只接受来自文本框的一个数据

MDI儿童表格:

    Private Delegate Sub DoSearch(Msg As String)
    Private PerformSearch As DoSearch

    Private Sub InvokeFunc(Msg As String)
        If PerformSearch IsNot Nothing Then
            PerformSearch .Invoke(Msg)
        End If
    End Sub

    Public Sub FuncDisplayMsg(Msg As String)
        msg(Msg)
    End Sub

    Private Sub FrmParentLoad(sender As Object, e As EventArgs)
        Dim FrmSecond As New frmSecondChild()           
        PerformSearch = AddressOf Me.FuncDisplayMsg
        FrmSecond.InvokeDel = AddressOf Me.InvokeFunc
        FrmSecond.Show()
    End Sub

对话框表格

    Public Delegate Sub SearchInvoke(Msg As String)
    Public InvokeSearch As SearchInvoke

    Private Sub btnSubmit_Click(sender As Object, e As EventArgs)
        If Me.InvokeSearch IsNot Nothing Then
            InvokeSearch .Invoke(Me.txtMsg.Text)
        End If
    End Sub

如何将控件(文本框,组合框和复选框)的值从对话框窗体传递到Active MDI子窗体(假设许多MDI子窗口打开),如图所示,并在MDI儿童

enter image description here

1 个答案:

答案 0 :(得分:2)

你似乎正在跳过一些太多的箍。你不需要两个代表。你只需要一个。例如,如果您的对话窗口有如下代码:

Public Delegate Sub SearchInvoke(selection As Object, msg As String, chk1 As Boolean, chk2 As Boolean)
Public Property InvokeSearch As SearchInvoke

Private Sub btnSubmit_Click(sender As Object, e As EventArgs)
    If Me.InvokeSearch IsNot Nothing Then
        InvokeSearch.Invoke(cboSelection.SelectedItem, txtMsg.Text, chkBox1.Checked, chkBox2.Checked)
    End If
End Sub

然后您可以在主窗体中使用如下代码:

Public Sub FuncDisplayMsg(selection As Object, msg As String, chk1 As Boolean, chk2 As Boolean)
    MessageBox.Show(msg)
End Sub

Private Sub FrmParentLoad(sender As Object, e As EventArgs)
    Dim FrmSecond As New frmSecondChild()           
    FrmSecond.InvokeSearch = AddressOf Me.FuncDisplayMsg
    FrmSecond.Show()
End Sub

使用类而不是多个参数

或者,您可以将所有数据打包在单个对象中,然后将该对象作为参数发送给委托。例如,如果你有这样一个类:

Public Class DialogData
    Public Property Selection As Object
    Public Property Msg As String
    Public Property Chk1 As Boolean
    Public Property Chk2 As Boolean
End Class

然后你可以定义你的委托并从对话框中调用它:

Public Delegate Sub SearchInvoke(data As DialogData)
Public Property InvokeSearch As SearchInvoke

Private Sub btnSubmit_Click(sender As Object, e As EventArgs)
    If Me.InvokeSearch IsNot Nothing Then
        InvokeSearch.Invoke(New DialogData() With 
                                {
                                .Selection = cboSelection.SelectedItem, 
                                .Msg = txtMsg.Text,
                                .Chk1 = chkBox1.Checked, 
                                .Chk2 = chkBox2.Checked
                                })
    End If
End Sub

您可以在主窗体中处理委托调用,如下所示:

Public Sub FuncDisplayMsg(data As DialogData)
    MessageBox.Show(data.Msg)
End Sub

Private Sub FrmParentLoad(sender As Object, e As EventArgs)
    Dim FrmSecond As New frmSecondChild()           
    FrmSecond.InvokeSearch = AddressOf Me.FuncDisplayMsg
    FrmSecond.Show()
End Sub

使用事件而不是代理

从技术上讲,事件只是一种特殊的委托,所以它们有效地以同样的方式工作。但是,用于处理事件的VB.NET语法与使用标准委托有很大不同。由于处理事件很常见,您可能会发现它更常见"正常"将其实现为事件而不是标准委托。要正确地执行此操作,您需要创建一个包含用于保存数据的属性的EventArgs类(类似于之前讨论的DialogData类),例如:

Public Class SearchSubmittedEventArgs
    Inherits EventArgs

    Public Property Selection As Object
    Public Property Msg As String
    Public Property Chk1 As Boolean
    Public Property Chk2 As Boolean
End Class

然后,您可以从对话框表单中声明并引发事件,如下所示:

Public Event SearchSubmitted As EventHandler(Of SearchSubmittedEventArgs)

Private Sub btnSubmit_Click(sender As Object, e As EventArgs)
    RaiseEvent SearchSubmitted(Me, New SearchSubmittedEventArgs() With 
                                           {
                                           .Selection = cboSelection.SelectedItem, 
                                           .Msg = txtMsg.Text,
                                           .Chk1 = chkBox1.Checked, 
                                           .Chk2 = chkBox2.Checked
                                           })
End Sub

然后你就可以在你的主表单上处理这个事件:

Private WithEvents _dialog As frmSecondChild

Private Sub _dialog_SearchSubmitted(sender As Object, e As SearchSubmittedEventArgs) Handles _dialog.SearchSubmitted
    MessageBox.Show(e.Msg)
End Sub

Private Sub FrmParentLoad(sender As Object, e As EventArgs)
    _dialog = New frmSecondChild()           
    _dialog.Show()
End Sub

您还可以选择使用WithEvents和关键字手动附加事件处理程序,而不是使用HandlesAddHandler关键字。但是,如果您这样做,请不要忘记以后使用RemoveHandler分离它。

将业务对象传递给对话而不是代理

另一个选择是放弃拥有委托或事件,而是选择向对话框表单提供一些业务对象。然后,对话框表单可以在该业务类上调用方法,以根据需要执行搜索。例如,如果您创建了这样的业务类:

Public Class SearchBusiness
    Public Sub PerformSearch(selection As Object, msg As String, chk1 As Boolean, chk2 As Boolean)
        MessageBox.Show(msg)
    End Sub
End Class

然后你可以根据需要从对话框表单中调用它,如下所示:

Public Property Business As SearchBusiness

Private Sub btnSubmit_Click(sender As Object, e As EventArgs)
    If Business IsNot Nothing Then
        Business.PerformSearch(cboSelection.SelectedItem, txtMsg.Text, chkBox1.Checked, chkBox2.Checked)
    End If
End Sub

您可以从父表单中显示对话框表单,如下所示:

Private Sub FrmParentLoad(sender As Object, e As EventArgs)
    Dim FrmSecond As New frmSecondChild()           
    FrmSecond.Business = New SearchBusiness()
    FrmSecond.Show()
End Sub

虽然在这种情况下,除非有不同类型的搜索业务类都继承自SearchBusiness,但是当对话框可以创建业务对象时,让父表单成为创建业务对象的东西似乎很愚蠢本身。这让我想到了下一个选择...

使用接口使业务对象可互换

由于对话框表单明确使用了单独的业务类,这有点紧缩,在我看来,更好的方法是为搜索业务创建一个接口,如下所示:

Public Interface ISearchBusiness
    Sub PerformSearch(selection As Object, msg As String, chk1 As Boolean, chk2 As Boolean)
End Interface

Public Class SearchBusiness
    Implements ISearchBusiness

    Public Sub PerformSearch(selection As Object, msg As String, chk1 As Boolean, chk2 As Boolean) Implements ISearchBusiness.PerformSearch
        MessageBox.Show(msg)
    End Sub
End Class

然后,您可以从对话框表单中调用它:

Public Property Business As ISearchBusiness

Private Sub btnSubmit_Click(sender As Object, e As EventArgs)
    If Business IsNot Nothing Then
        Business.PerformSearch(cboSelection.SelectedItem, txtMsg.Text, chkBox1.Checked, chkBox2.Checked)
    End If
End Sub

您可以从主表单中将对应的业务对象提供给对话框,方法与上面相同,如下所示:

Private Sub FrmParentLoad(sender As Object, e As EventArgs)
    Dim FrmSecond As New frmSecondChild()           
    FrmSecond.Business = New SearchBusiness()
    FrmSecond.Show()
End Sub

将父表单传递给对话而不是单独的业务对象

如果由于设计中的不明智限制,只有父表单能够执行业务逻辑,那么您可以为对话框提供对父表单的引用,而不是单独的业务对象。但是,在这种情况下,我肯定会坚持使用界面。这样,您可以在以后重构代码,为对话框提供一个单独的业务对象,该对象实现相同的接口而不是父窗体。你不会想把这种糟糕的设计搞得一团糟。所以,如果你有与上面相同的界面:

Public Interface ISearchBusiness
    Sub PerformSearch(selection As Object, msg As String, chk1 As Boolean, chk2 As Boolean)
End Interface

然后你仍然以同样的方式从对话框中调用它,如上所述:

Public Property Business As ISearchBusiness

Private Sub btnSubmit_Click(sender As Object, e As EventArgs)
    If Business IsNot Nothing Then
        Business.PerformSearch(cboSelection.SelectedItem, txtMsg.Text, chkBox1.Checked, chkBox2.Checked)
    End If
End Sub

然后你可以在你的父窗体中实现这样的接口:

Public Class FrmParent
    Implements ISearchBusiness

    Public Sub PerformSearch(selection As Object, msg As String, chk1 As Boolean, chk2 As Boolean) Implements ISearchBusiness.PerformSearch
        MessageBox.Show(msg)
    End Sub

    Private Sub FrmParentLoad(sender As Object, e As EventArgs)
        Dim FrmSecond As New frmSecondChild()           
        FrmSecond.Business = Me
        FrmSecond.Show()
    End Sub
End Class

以模态方式显示对话框

当以模态方式显示表单时(即使用ShowDialog方法而不是Show方法),这意味着在关闭对话框表单之前,执行不会在父表单中继续。因此,如果您不介意对话框从用户窃取并保持焦点直到完成(这是对话框窗口的典型行为),那么您可以只是以模态方式显示对话框表单然后阅读它的属性一旦关闭。例如,在您的主要表单中,您可以执行以下操作:

Private Sub FrmParentLoad(sender As Object, e As EventArgs)
    Dim FrmSecond As New frmSecondChild()           
    FrmSecond.ShowDialog()
    MessageBox.Show(FrmSecond.txtMsg.Text)
End Sub
但是,直接访问另一个表单上的控件并不是一个好习惯。如果对话框形成每个数据的公开属性,然后主表单通过这些属性访问数据,那会更好。

这种方法是迄今为止最简单的方法。你可以在任何地方这样做,这是有道理的。例如,设计了OpenFileDialogColorDialog以及.NET框架内置的其他对话框的方式。然而,这种设计有一个主要缺点,它可能限制其使用。如果您需要保持对话框打开,直到工作完成,那么您无法以这种方式实现。例如,您可能希望在执行搜索时在对话框上显示某种进度条。或者,您可能希望允许业务逻辑中可能出现某些验证错误,此时您希望用户能够对对话框进行更改,然后再次尝试。在对话框用于数据输入的情况下,后者尤其令人担忧。例如,如果对话框用于允许用户提交新的销售订单,那么在销售订单成功提交之前,您不希望关闭对话框。如果在将数据保存到系统时发生某些故障,那么您可能希望让他们解决问题,然后尝试再次提交。