mercenary
mercenary

Reputation: 69

How to pass multiple info to MDI Child Form from another modal dialog form

I try using delegate to pass info from dialog form to active MDI child form(not parent form) but it only accepts one data, how to I do this with multiple data like shown in the picture below:

this is I use so far: it only accepts one data from textbox

MDI Child Form:

    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

Dialog Form

    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

How do I pass the values of a control(textbox, combobox & checkbox) from a dialog form to an Active MDI Child Form (assuming many MDI Child is open) like shown in a picture, and perform the search within the MDI Child

enter image description here

Upvotes: 2

Views: 1679

Answers (1)

Steven Doggart
Steven Doggart

Reputation: 43743

You seem to be jumping through a few too many hoops. You don't need two delegates. You only need one. For instance, if your dialog window had code like this:

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

Then you could simply have code in your main form that looked like this:

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

Using a Class Instead of Multiple Parameters

Alternatively, you could package all of the data in a single object and then send that one object as a parameter to the delegate. For instance, if you had a class like this:

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

Then you could define your delegate and call it from the dialog form like this:

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

And you could handle the delegate invocation in your main form like this:

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

Using an Event Instead of a Delegate

Technically, an event is just a special kind of delegate, so they effectively work in the same way. However, the VB.NET syntax for working with events is considerably different than working with standard delegates. Since handling events is commonplace, you may find it more "normal" to implement it as an event rather than a standard delegate. To do that properly, you'd want to make an EventArgs class that contains properties to hold the data (similar to the previously discussed DialogData class), for instance:

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

Then, you could declare and raise the event from the dialog form like this:

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

And then you could handle the event on your main form like this:

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

Rather than using the WithEvents and Handles keywords, you could also choose to manually attach the event handler using the AddHandler and keyword. However, if you do that, don't forget to later detach it using RemoveHandler.

Passing a Business Object to the Dialog Instead of a Delegate

Another option would be to forgo having a delegate or event at all, and instead choose to give some business object to the dialog form. The dialog form could then just call a method on that business class to perform the search as needed. For instance, if you created a business class like this:

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

Then you could just call it, as necessary, from the dialog form like this:

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

And you could show the dialog form from the parent form like this:

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

Although, in that case, unless there are different kinds of search business classes which all inherit from SearchBusiness, it seems silly to have the parent form be the thing creating the business object when the dialog could just create it itself. Which leads me to the next option...

Using an Interface to Make the Business Object Interchangeable

Since having the separate business class being used explicitly by the dialog form is a bit constricting, the preferable method, in my mind, would be to create an interface for the search business, like this:

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

Then, you could call it from the dialog form like this:

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

And you could give the applicable business object to the dialog from your main form, the same way as above, like this:

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

Passing the Parent Form to the Dialog Instead of a Separate Business Object

If, due to an unwise limitation in your design, only the parent form is capable of performing the business logic, then you could give the dialog a reference to the parent form rather than to a separate business object. However, in that case, I would definitely stick with using an interface. That way, you could, at a later date, refactor the code to give the dialog a separate business object that implements the same interface rather than the parent form. You wouldn't want to cement that poor design in stone. So, if you had the same interface as above:

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

Then you'd still call it from the dialog in the same way, as above:

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

Then you could implement the interface in your parent form like this:

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

Displaying the Dialog Modally

When a form is displayed modally (i.e. using the ShowDialog method rather than the Show method), that means that execution does not continue in the parent form until the dialog form has been closed. Therefore, if you don't mind the dialog form stealing and holding onto the focus from the user until it is done (which is the typical behavior of a dialog window), then you could just show the dialog form modally and then read its properties once it is closed. For instance, in your main form you could just do something like this:

Private Sub FrmParentLoad(sender As Object, e As EventArgs)
    Dim FrmSecond As New frmSecondChild()           
    FrmSecond.ShowDialog()
    MessageBox.Show(FrmSecond.txtMsg.Text)
End Sub

It's not good practice, though, to access controls on another form directly like that. It would be better if the dialog form exposed properties for each datum and then the main form accessed the data through those properties.

This method is by far the simplest. Anywhere you can do it like this, it makes sense. This is, for instance the way the OpenFileDialog, ColorDialog, and other dialogs that are built-in to the .NET framework are designed. This design has one major drawback, though, which can limit its use. If you need to keep the dialog open until the work is complete, then you can't really do it this way. For instance, you may want to display some sort of progress bar on the dialog while the search was being performed. Or, you may want to allow for the fact that some validation error may occur in the business logic at which point you'd want the user to be able to make changes on the dialog and then try again. The latter is of particular concern in cases where the dialog is being used for data entry. For instance, if the dialog was being used to allow the user to submit a new sales order, then you don't want to close the dialog until the sales order has been successfully submitted. If some failure occurs while the data is being saved to the system, then you will likely want to let them fix the problem and then try submitting it again.

Upvotes: 2

Related Questions