sub event to interact with more than one control - vb.net

I want to call this snippet passing a "controlname" like a argument, then the sub interacts with the desired control
How I can do that?
This is the snippet:
#Region " Move a control in real-time "
' Change Textbox1 to the desired control name
Private Sub TextBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles textbox1.MouseDown
If e.Button = Windows.Forms.MouseButtons.Left Then
textbox1.Capture = False
Dim ControlMoveMSG As Message = Message.Create(textbox1.Handle, &HA1, New IntPtr(2), IntPtr.Zero)
Me.DefWndProc(ControlMoveMSG)
End If
End Sub
#End Region
UPDATE:
The solution:
Private Sub MoveControl(sender As Object, e As EventArgs) Handles _
TextBox1.MouseDown, _
TextBox2.MouseDown, _
PictureBox1.MouseDown
Dim control As Control = CType(sender, Control)
control.Capture = False
Dim ControlMoveMSG As Message = Message.Create(control.Handle, &HA1, New IntPtr(2), IntPtr.Zero)
Me.DefWndProc(ControlMoveMSG)
End Sub

In this case, you can just use sender. The sender parameter is a reference to whichever control is raising the event. So, if you add this same method as an event handler for multiple controls, sender will be which ever control raised the event that it's currently handling, for instance:
Private Sub MouseDown(sender As Object, e As EventArgs) _
Handles TextBox1.MouseDown, TextBox2.MouseDown
' Note in the line above that this method handles the event
' for TextBox1 and TextBox2
Dim textBox As TextBox = CType(sender, TextBox)
' textBox will now be either TextBox1 or TextBox2, accordingly
textBox.Capture = False
' ....
End Sub
The CType statement casts the base Object parameter to the specific TextBox class. In this example, the method only handles events for TextBox objects, so that will work. However, if you have it handle events from other types of controls, you'd need to cast to the more general Control type (i.e. CType(sender, Control)).

Related

VB.net - How to send multiple senders to event handler

I have MonthlyCalendar created and shown once a text box is clicked "e.g. Date of Birth". I do have multiple dates text boxes in my Form and I would like to send the actual text box as Object "clicked" along with the MonthlyCalendar as Sender as well , 3 arguments.
Private Sub TextBox1_Click(sender As Object, e As EventArgs) Handles txtDOB.Click
Dim mc = New MonthCalendar()
AddHandler mc.DateSelected, AddressOf DateSelected
Me.Controls.Add(mc)
mc.BringToFront()
mc.Show()
End Sub
Private Sub DateSelected(sender As Object, e As DateRangeEventArgs) Handles MonthCalendar1.DateSelected
txtDOB.Text = DirectCast(sender, MonthCalendar).SelectionRange.Start.Date.ToString("yyyyMMdd")
End Sub
I would like the handler to be like this:
1st argument the actual textbox clicked 2nd argument the Monthly Calendar 3rd argument the DateRangeEventArgs
AddHandler mc.DateSelected, AddressOf DateSelected(sender 'Textbox as Object, sender 'MontlyCalendar As Object, e As DateRangeEventArgs)
Appreciate guidance and a better way of doing this
Here's the way I'd do this. I'd avoid all of that casting you're doing.
Private Sub AnyTextBox_Click(sender As Object, e As EventArgs) Handles txtDOB.Click, txt2.Click, txt3.Click
Dim tb = CType(sender, TextBox)
Dim mc = New MonthCalendar()
AddHandler mc.DateSelected, Sub (s2, e2) mc.SelectionRange.Start.Date.ToString("yyyyMMdd")
Me.Controls.Add(mc)
mc.BringToFront()
mc.Show()
End Sub
This also avoids the separate DateSelected handler. Much cleaner and even more strongly typed.
The next step in making the code cleaner is to handle the closing down of your MonthCalendar control. Your current code and my code above doesn't do it.
Here's how:
Private Sub AnyTextBox_Click(sender As Object, e As EventArgs) Handles txtDOB.Click, txt2.Click, txt3.Click
Dim tb = CType(sender, TextBox)
Dim mc = New MonthCalendar()
Dim handler As EventHandler(Of DateRangeEventArgs) = _
Sub(s2, e2)
mc.SelectionRange.Start.Date.ToString("yyyyMMdd")
Me.Controls.Remove(mc)
RemoveHandler mc.DateSelected, handler
End Sub
AddHandler mc.DateSelected, handler
Me.Controls.Add(mc)
mc.BringToFront()
mc.Show()
End Sub
You don't send anything to an event handler. The object itself raises the event in response to something done to it and it sends the arguments to the event handler. You can't change the signature and you can't choose what arguments it receives.
Probably your best bet would be to, when you create the MonthCalendar, assign the corresponding TextBox to its Tag property.
Dim mc = New MonthCalendar With {.Tag = sender}
Tag is a general-purpose data property of type Object, so there's no need to cast sender at this point. You know that the actual object is a TextBox, because that's all that will raise that event.
In the event handler, you can then get the MonthCalendar from the sender and the TextBox from its Tag.
Dim mc = DirectCast(sender, MonthCalendar)
Dim tb = DirectCast(mc.Tag, TextBox)

Call a control event handler with multiple controls

Private Sub NullValidation(sender As Object, e As EventArgs) Handles FirstNameTextBox.Validating,
LastNameTextBox.Validating, FatherNameTextBox.Validating,
If String.IsNullOrWhiteSpace(sender.Text) Then
ErrorProvider1.SetError(sender, "Text box is empty ")
End If
End Sub
I want to check my controls validation out of this event handler (in a button click handler). But as it requires sender and e arguments it won't works. How can I do it?
Because number of controls are more than what I have wrote here(more than just FirstNameTextBox and LastNameTextBox), it doesn't seem a good solution to write a validation code for every one of them. But as it requires sender and e arguments it won't works. How can I do it?
First thing you should do is to set option strict on. You're not using the correct method signature. The validating event is defined as:
Public Delegate Sub CancelEventHandler(ByVal sender As Object, ByVal e As CancelEventArgs)
Change the type of e from EventArgs to CancelEventArgs. You may need to import the namespace System.ComponentModel. Then set e.Cancel to True to indicate that the validation didn't pass.
Private Sub NullValidation(sender As Object, e As CancelEventArgs) Handles FirstNameTextBox.Validating, LastNameTextBox.Validating, FatherNameTextBox.Validating
Dim ctl As Control = TryCast(sender, Control)
If ((Not ctl Is Nothing) AndAlso String.IsNullOrWhiteSpace(ctl.Text)) Then
e.Cancel = True
Me.ErrorProvider1.SetError(ctl, "Text box is empty ")
End If
End Sub

Get combobox selected from another form dynamically

I have a combobox in a form1 and a datagridview in another form2.
I want to get the combobox selected with a value from the datagridview in the second form
I use the code below in form2 and it works:
Private Sub DataGridView1_CellDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
form1.CBO_fournisseur.Text = DataGridView1.Rows(e.RowIndex).Cells(0).Value.ToString
Me.Close()
End Sub
But what I want to do is that the name of the form is passed dynamically to avoid using and IFELSE clause to enumerate all the forms I have in my project that use form2
Private Sub DataGridView1_CellDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
If formbon2.Name = "FRM_BN_RECEPTION_CUIR" Then
FRM_BN_RECEPTION_CUIR.CBO_fournisseur.Text = DataGridView1.Rows(e.RowIndex).Cells(0).Value.ToString
ElseIf formbon2.Name = "frm_reception_acc_provisoire" Then
frm_reception_acc_provisoire.CBO_1.Text = DataGridView1.Rows(e.RowIndex).Cells(0).Value.ToString
End If
Me.Close()
End Sub
I think I've got what you want to do. I strongly suggest you stop using the Form as a Shared resource.
Use a constructor like this in your Form2:
Private ParentFormCombo as Combobox
Public Sub New(ByVal pCmb as Combobox)
ParentFormCombo = pCmb
End Sub
Then in your doubleclick you just change the text of ParentFormCombo
ParentFormCombo.Text = DataGridView1.Rows(e.RowIndex).Cells(0).Value.ToString
Then you have to stop using:
FrmList_View.Show()
Now you should always use the constructor instead (New()). So do the following instead:
Dim f As New FrmList_View(CBO_fournisseur)
'or
Dim f As New FrmList_View(CBO_1)
f.Show()

Custom control mybase.OnTextChanged not firing

I have a custom text box control which validates input (striped out unwanted chars). This works fine apart from when I also want to do further processing on an implementation of the control.
Example I have 3 "specialTextbox"s on a form. sText1, sText2 and sText3. sText1 & sText2 work as as intended. However, I need to make changes on the forum when the value of sText3 is changed, so I have a handler in the form to handle the ctext changed event:
Private Sub sText3(sender As Object, e As EventArgs) Handles sText3.TextChanged
'do some stuff here
End Sub
However this routine appears to override the OnTextChanged method of the custom text box. I have tried includeing a call to MyBase.OnTextChanged, but this still doesn't cascade up and no matter what I do I can't seem to get the text box to do its validation duties.
Must be something really simple, but I'm stumped!
Here is a class which overrides textbox
Public Class restrictedTextBox
Inherits Windows.Forms.TextBox
Protected validChars As List(Of Char)
Public Sub New(ByVal _validChars As List(Of Char))
MyBase.New()
validChars = _validChars
End Sub
Public Sub setValidChars(ByVal chrz As List(Of Char))
validChars = chrz
End Sub
Protected Overrides Sub OnTextChanged(e As System.EventArgs)
MyBase.OnTextChanged(e)
Dim newValue As String = ""
For Each c As Char In Me.Text.ToCharArray
Dim valid As Boolean = False
For Each c2 As Char In validChars
If c = c2 Then valid = True
Next
If valid Then newValue &= c.ToString
Next
Me.Text = newValue
End Sub
End Class
Here is a form which has a a custom textbox
Public Class frmNewForm
Private Sub btnOK_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnOK.Click
MessageBox.Show("the text from the restricted text is: " & txtRestricted.Text)
End Sub
End Class
Here is a form with a custom text box, which implements the TextChanged event
Public Class frmNewForm2
Private Sub btnOK_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnOK.Click
MessageBox.Show("the text from the restricted text is: " & txtRestricted.Text)
End If
Private Sub txtRestricted_TextChanged(sender As Object, e As EventArgs) Handles txtRestricted.TextChanged
'now that I have implemented this method, the restrictedTextBox.OnTextChanged() doesn't fire - even if I call MyBase.OnTextChanged(e)
'just to be completely clear. the line of code below DOES get executed. But the code in restrictedTextBox.vb does NOT
lblAwesomeLabel.Text=txtRestricted.Text
End Sub
End Class
It fires, but probably not the way you are implementing it.
Your sample code does not have an empty constructor for the textbox, which means you are most likely not using the designer when you are adding the textbox to the form.
But your form shows it was created by the designer:
Private Sub txtRestricted_TextChanged(sender As Object, e As EventArgs) _
Handles txtRestricted.TextChanged
End Sub
That's not possible with your posted code. If you are creating "new" controls programmatically, then you need to wire up the events programmatically, too.
Drop the handler and just leave the stub:
Private Sub txtRestricted_TextChanged(sender As Object, e As EventArgs)
'yada-yada-yada
End Sub
then when you create a new textbox, wire it up:
txtRestricted = new restrictedTextBox(myCharsList)
AddHandler txtRestricted.TextChanged, AddressOf txtRestricted_TextChanged
Me.Controls.Add(txtRestricted)

Validating Textboxs

I am doing a simple aplication using Windows Forms and I have a question...
My form has 15 textboxs and I want to validate everyone using the event KeyPress or validating. I have this code that is working:
If Not IsNumeric(txtn1.Text) Then
e.Cancel = True
ErrorProvider1.SetError(txtn1, "")
Else
something(txtn1.text)
End If
But I have 15 textboxs (maybe more) and is a little humdrum copy/pase this code in every textbox event. Can you teach me to do this using a function?
Public Function isnum(ByVal txt As TextBox, ByVal errpro as ErrorProvider) As Double
If Not IsNumeric(txt.Text) Then
e.Cancel = True <-------------------------------This dont work
errpro.SetError(txt, "")
End If
End Function
Private Sub txtn1_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles txtKLDC.Validating
if isnum(txtn1, ErrorProvider1) then
something(txtn1.text)
end if
I´m looking for the correct way to do this?
English is my second language and I'm learning programming too.
Use a common KeyPress event then use the sender object which is the TextBox that originated the Event and cast it to a TextBox.
Private Sub txt_KeyPress(sender As System.Object, e As System.Windows.Forms.KeyPressEventArgs) Handles txtn1.KeyPress, txtn2.KeyPress, txtn3.KeyPress, txtn4.KeyPress, txtn5.KeyPress
Dim tb As TextBox = CType(sender, TextBox)
If Not IsNumeric(tb.Text) Then
e.Handled = True
ErrorProvider1.SetError(tb, "")
Else
something(tb.Text)
End If
End Sub
With this code:
Private Sub NumericValidation_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) _
Handles TextBox1.KeyPress, TextBox2.KeyPress, upto 16500 or so is possible...
Dim txt As TextBox = CType(sender, TextBox)
If Not IsNumeric(txt.Text) Then
e.Cancel = True
ErrorProvider1.SetError(txt, "")
Else
something(txt.text)
End If
End Sub
Notice how I assign each one of the Textbox's KeyPress Event Handler to the single NumericValidation_KeyPress sub routine. I cast the sender into a Textbox to find out which textbox keypress event fired.