Multi parent form - vb.net

I've a vb .net winform that is show by others forms. I've frmA.vb, frmB.vb, frmC.vb and frmD.vb.
This all forms can call frmItem.vb.
frmItem.vb allows the user to select an item from a Database, this item is sent by calling a Set Property on the parent.
i.e.
I open frmA, click on button (something like:)
fi = new frmItem(frmA) 'frmItem has 4 New() methods, frmA.. b... c and d
'i need to pass the correct parent.
fi.showModal()
So, when i add an item, it calls
fA.addItem(item_id)
It works OK, my doubt is about optimization, because i've duplicated frmItem; one copy managed frmA and frmB, and the other one, frmC and frmD.
i.e.
in frmItem1 when i've to sent the item, i use:
private fB as frmB
private fA as frmA
if parentFrmA is nothing then
'Is frmB
fB.addItem(item_id)
else
'Is frmA
fA.addItem(item_id)
end if
And, on frmItem2:
private fC as frmC
private fD as frmD
if parentFrmC is nothing then
'Is frmD
fD.addItem(item_id)
else
'Is frmC
fC.addItem(item_id)
end if
If i modify frmItem1, i've to modify frmItem2 and viceversa, because they should look and act like one.
All four forms, have the same Set Property, but like they're differents forms, i can't use a unique Form class in frmItem.
Is the posibility that one form, can manage multi parents in an easy way??
If you need more info, let me know. Thanks

I can't completely follow your example since, well, I think it's just hard to follow.
But in general, it sounds like these child forms should just be raising an event that the parent form is listening for. That way, you can separate your concerns a bit and not hardcode these dependencies.
You can try making your own EventArgs class to follow best practices:
Public Class ChildFormEventArgs
Inherits EventArgs
Private _ItemID As Integer
Public Sub New(ByVal itemID As Integer)
_ItemID = itemID
End Sub
ReadOnly Property ItemID() As Integer
Get
Return _ItemID
End Get
End Property
End Class
Your child forms would have a public event and you would raise it when ever this "added" thing happens:
Public Class Form2
Public Event ItemAdded(ByVal sender As Object, ByVal e As ChildFormEventArgs)
Private _ItemID as Integer
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
RaiseEvent ItemAdded(Me, New ChildFormEventArgs(_ItemID))
End Sub
End Sub
And then your parent form is the one listening and can act accordingly:
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
Using testForm As New Form2()
AddHandler testForm.ItemAdded, AddressOf ChildForm_ItemAdded
testForm.ShowDialog(Me)
RemoveHandler testForm.ItemAdded, AddressOf ChildForm_ItemAdded
End Using
End Sub
Private Sub ChildForm_ItemAdded(ByVal sender As Object, ByVal e As ChildFormEventArgs)
'// do something here.
'// sender is the child form that called it
'// e is the event arguments that contains the ItemID value
End Sub

Related

Add combobox items from another usercontrol form using textbox

I have a usercontrol form named "ucSETTINGS", where there is a textbox and once the button was clicked, the text inside the textbox will be added to the combobox from another usercontrol form name "ucITEMS"
I tried this code but it's not working
(cboCategory is the name of the combobox from ucITEMS, txtNAME is the textbox from ucSETTINGS)
Private Sub btnSAVE_Click(sender As Object, e As EventArgs) Handles btnSAVE.Click
Dim category As New ucITEMS()
category.cboCATEGORY.Items.Add(txtNAME.Text)
End Sub
Can someone help me?
In this sort of situation, the user controls don't know about each other by default and it should stay that way. The source UC just exposes an interface and lets whomever is watching use that as it sees fit. That means raising an event when something happens and exposing required data via properties, e.g.
Public Class SourceControl
Public ReadOnly Property TextBox1Text As String
Get
Return TextBox1.Text
End Get
End Property
Public Event Button1Click As EventHandler
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
OnButton1Click(EventArgs.Empty)
End Sub
Protected Overridable Sub OnButton1Click(e As EventArgs)
RaiseEvent Button1Click(Me, e)
End Sub
End Class
The Text of the TextBox is exposed via a property and, when the user clicks the Button, the UC raises an event.
The destination UC provides an interface for new items to be provided but it adds them to its own ComboBox, e.g.
Public Class DestinationControl
Public Sub AddItemToComboBox1(item As Object)
ComboBox1.Items.Add(item)
End Sub
End Class
The form then plays go-between, handling the event, getting the property and calling the method:
Private Sub SourceControl1_Button1Click(sender As Object, e As EventArgs) Handles SourceControl1.Button1Click
DestinationControl1.AddItemToComboBox1(SourceControl1.TextBox1Text)
End Sub
Obviously you would use something more specific and appropriate than my generic naming.

VB.NET User control Referencing Form

I have a form (frmwizard) which I am using to create a wizard like interface. The form contains a usercontrol and a button (for testing). There is also a function on the form called "NextPage"
The form loads a usercontrol (ucpage1) on load and the usercontrol has a button on it that when clicked attempts to call a function on the main form as per below:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
frmWizard.Nextpage(me.name)
End Sub
Within my function called "NextPage" have the following for testing.
Public Sub NextPage(ByVal CurrentPage As String)
MessageBox.Show(UserControl1.Controls.Count)
End Sub
When I call the function from the form itself (via the button) I get the result of 1, when i call the function via the User Control, I get the result as 0
I'm sure there is something simple I need to do, but i'm unsure what i've overlooked.
I am trying to make the button on the user-control Save the data within the control and then to browse to the next wizard page. Hopefully this is enough information
Codependance is a bad idea, as it locks the two types together for the future. If your user control really needs to invoke the form, you should instead have it raise an event and handle the event in your form.
Public Class MyUserControl
Public Event OnNextPage(ByVal sender As Object, ByVal e As EventArgs)
Private Sub btnNextPage_Click(sender As Object, e As EventArgs) Handles btnNextPage.Click
RaiseEvent OnNextPage(Me, New EventArgs)
End Sub
End Class
Public Class Form1
Private Sub MyUserControl_OnNextPage(sender As Object, e As EventArgs) Handles MyUserControl1.OnNextPage ' , MyUserControl2.OnNextPage, etc...
MessageBox.Show(DirectCast(sender, MyUserControl).Controls.Count)
End Sub
End Class

Call function outside user control

I need help to call a function in a usercontrol that is shown in a panel within the form, so far this is i tried, but no luck, i can't still get the text inputted on the textbox
Public Class Form1
Private Sub LinkLabel1_LinkClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles LinkLabel1.LinkClicked
Dim ustudent As New StudentAdd
ustudent.Dock = DockStyle.Fill
SplitContainer1.Panel2.Controls.Add(ustudent)
End Sub
Private Sub ToolStripButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripButton1.Click
ustudent.SaveData()
End If
End Sub
End Class
in user control have some textbox
textbox1 and textbox2
Public Class StudentAdd
Public Sub SaveData() As Boolean
'just testing whether it could work well
' getting textbox value
MsgBox(TextBox1.Text)
End Sub
End Class
But ustudent is a local var, try to declare it outside link_clicked event. Do you want to create multiple user controls in the win or just one?
For one you could add it at design time by dragging from the your project components panel
For more, you should implement some logic to identify the selected component and make it available for save data. If you want to save all just enumerate components in Panel2 (of type StudentAdd) and call the method

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
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.

event detection between different controls vb

I have a class A which contains 2 user controls declared as
Friend WithEvents CustInfo1 As WindowsApplication1.CustInfo
Friend WithEvents ServiceLocation1 As WindowsApplication1.ServiceLocation
Both have textBoxes. If value of textBoxA in custInfo1 changes then how can I make value of textBoxB in SeviceLocation1 also change
I will be most thankful if anyone can help me.
Thanks
You need to do the following:
Inside the CustInfo user control, you need to write code inside the textBoxA Changed event that raises an event from the CustInfo user control (e.g. TextBoxChanged event). RaiseEvent statement
Inside the ServiceLocation user control, create a public property getter and setter for whatever your textBoxB.Text is
On the form that contains both user controls, create code in the new CustInfo TextBoxChanged event and set the new property on the ServiceLocation1 user control.
All controls (also custom controls) have the property Controls, through which you can access the (sub) controls of that control. Now you can retrieve your textbox by calling the .Item(key) method on it. Then you can assign a event handler to it in your form or class.
Dim key As String = "textBoxA" 'Or simply the name of that TextBox in your CustInfo
Dim textboxA As TextBox = CustInfo1.Controls.Item(key)
AddHandler textBoxA.TextChanged, AddressOf mytextchangedhandler
Where that mytextchangedhandler handles the TextChanged event for that TextBox.
Personally I don't like this method too much, as you are relying on knowing either the name of the TextBox or the index in the Controls list of your usercontrol.
I would definitely go for the option to create your own event on your usercontrol. It is quite easy to do even! Below how to do it. In the code behind of your usercontrol, you'll have to add an event declaration:
Event MyTextBoxChanged(sender As Object, e As EventArgs)
Now we'll have to raise it, we do this by implementing the TextChanged event of the TextBoxA in your usercontrol (as you explained you wanted to do):
Private Sub TextBoxA_TextChanged(sender As System.Object, e As System.EventArgs) Handles TextBoxA.TextChanged
RaiseEvent MyTextBoxChanged(Me, EventArgs.Empty)
End Sub
Now we can simply implement this event (MyTextBoxChanged) in your Form as follows:
Private Sub CustInfo1_MyTextBoxChanged(sender As System.Object, e As System.EventArgs) Handles CustInfo1.MyTextBoxChanged
' Do something
End Sub
Obviously we still need to get the updated text, now we can create our own EventArgs that will give us the new (and/or old value) as you will want to have. We simply can inherit the System.EventArgs class and add some properties (for example a property OldText that holds the old text value and a property NewText that holds the new text value):
Public Class MyEventArgs
Inherits System.EventArgs
Private _OldText As String
Public ReadOnly Property OldText() As String
Get
Return _OldText
End Get
End Property
Private _NewText As String
Public ReadOnly Property NewText() As String
Get
Return _NewText
End Get
End Property
Public Sub New(oldText As String, newText As String)
_OldText = oldText
_NewText = newText
End Sub
End Class
Now we have to change the event definition and raising to use the MyEventArgs:
Event MyTextBoxChanged(sender As Object, e As MyEventArgs)
Private Sub TextBoxA_TextChanged(sender As System.Object, e As System.EventArgs) Handles TextBoxA.TextChanged
RaiseEvent MyTextBoxChanged(Me, New MyEventArgs(TextBoxA.Text))
End Sub
And also change the implementation in your Form:
Private Sub CustInfo1_MyTextBoxChanged(sender As System.Object, e As MyEventArgs) Handles CustInfo1.MyTextBoxChanged
MessageBox.Show(e.Text)
End Sub
More information about events can be found on our favorite spot MSDN.