Reputation: 69
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
Upvotes: 2
Views: 1679
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
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
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
.
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...
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
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
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