I created a project one year ago and now I want to add background color to all the focused textboxes.
I know I can create the events for all textboxes but it will take a lot of time, and I know that I can create a custom control (textbox) but I don't prefer.
so can I add those events for all textboxes in my project?
Let's go through all the possibilities here.
Firstly, the usual thing to do with events is to create a distinct handler for each event of each control, e.g.
Private Sub TextBox1_Enter(sender As Object, e As EventArgs) Handles TextBox1.Enter
'...
End Sub
Private Sub TextBox1_Leave(sender As Object, e As EventArgs) Handles TextBox1.Leave
'...
End Sub
Private Sub TextBox2_Enter(sender As Object, e As EventArgs) Handles TextBox2.Enter
'...
End Sub
Private Sub TextBox2_Leave(sender As Object, e As EventArgs) Handles TextBox2.Leave
'...
End Sub
If you're doing the same thing for the same event of each control though, you can condense that into a single event handler per event:
Private Sub TextBoxes_Enter(sender As Object, e As EventArgs) Handles TextBox1.Enter, TextBox2.Enter
Dim tb = DirectCast(sender, TextBox)
'...
End Sub
Private Sub TextBoxws_Leave(sender As Object, e As EventArgs) Handles TextBox1.Leave, TextBox2.Leave
Dim tb = DirectCast(sender, TextBox)
'...
End Sub
The sender parameter refers to the object that raised the event, so you can access the appropriate TextBox with a cast. The objects whose event you handle don't have to be the same type and you can even handle multiple events with the one method, as long as the signatures are compatible:
Private Sub Controls_FocusChanged(sender As Object, e As EventArgs) Handles TextBox1.Enter,
TextBox2.Enter,
ComboBox1.Enter,
TextBox1.Leave,
TextBox2.Leave,
ComboBox1.Leave
Dim cntrl = DirectCast(sender, Control)
'The event is raised before the change happens so the control
'will have focus on Leave and will not have focus on Enter.
cntrl.BackColor = If(cntrl.Focused, SystemColors.Window, Color.Yellow)
End Sub
Note that the designer can help you do this. You can select multiple controls, open the Properties window, click the Events button and then double-click the desired event to generate a single event handler with the selected event for all selected controls in the Handles clause. You can then select that existing event handler in the drop-down list for another event for one or more controls to add then to the Handles clause too. You can edit the method name in the code window as appropriate. You can also write the method and the Handles clause yourself if you want to.
Secondly, to write less code in each form, you can put your event handler(s) in a module somewhere and then use the AddHandler statement to attach it to the events when a form loads:
Module CommonEventHandlers
Public Sub Controls_FocusChanged(sender As Object, e As EventArgs)
Dim cntrl = DirectCast(sender, Control)
'The control will have focus on Leave and will not have focus on Enter.
cntrl.BackColor = If(cntrl.Focused, SystemColors.Window, Color.Yellow)
End Sub
End Module
and:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each tb In Controls.OfType(Of TextBox)()
AddHandler tb.Enter, AddressOf CommonEventHandlers.Controls_FocusChanged
AddHandler tb.Leave, AddressOf CommonEventHandlers.Controls_FocusChanged
Next
End Sub
Private Sub Form1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
For Each tb In Controls.OfType(Of TextBox)()
RemoveHandler tb.Enter, AddressOf CommonEventHandlers.Controls_FocusChanged
RemoveHandler tb.Leave, AddressOf CommonEventHandlers.Controls_FocusChanged
Next
End Sub
That will handle the events for all TextBoxes that were added directly to the form. If you want different controls and/or some are in child containers then you would need to adjust that accordingly. Note that the event handlers need to be removed when you're done.
Finally, the "proper" solution is to use a custom control. You create a custom control simply by adding a class to your project and then adding an Inherits line to that class. You then override the appropriate method for the event you would otherwise handle, e.g. OnEnter method for Enter event. The code you put in the method is basically the same as you would put in the event handler, except it refers to the current object rather than the sender:
Public Class TextBoxEx
Inherits TextBox
Private defaultBackColor As Color
''' <inheritdoc />
Protected Overrides Sub OnEnter(e As EventArgs)
defaultBackColor = BackColor
BackColor = Color.Yellow
MyBase.OnEnter(e)
End Sub
''' <inheritdoc />
Protected Overrides Sub OnLeave(e As EventArgs)
BackColor = defaultBackColor
MyBase.OnLeave(e)
End Sub
End Class
You can then just edit the designer code files of your existing forms to use that custom control instead of the standard TextBox, e.g. this:
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
Me.TextBox1 = New System.Windows.Forms.TextBox()
Me.SuspendLayout()
'
'TextBox1
'
Me.TextBox1.Location = New System.Drawing.Point(0, 0)
Me.TextBox1.Name = "TextBox1"
Me.TextBox1.Size = New System.Drawing.Size(100, 20)
Me.TextBox1.TabIndex = 0
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(800, 450)
Me.Controls.Add(Me.TextBox1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
Me.PerformLayout()
End Sub
Friend WithEvents TextBox1 As TextBox
becomes this:
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
Me.TextBox1 = New TextBoxEx()
Me.SuspendLayout()
'
'TextBox1
'
Me.TextBox1.Location = New System.Drawing.Point(0, 0)
Me.TextBox1.Name = "TextBox1"
Me.TextBox1.Size = New System.Drawing.Size(100, 20)
Me.TextBox1.TabIndex = 0
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(800, 450)
Me.Controls.Add(Me.TextBox1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
Me.PerformLayout()
End Sub
Friend WithEvents TextBox1 As TextBoxEx
That's just two lines of code changed per control, which you can do with the Find & Replace functionality. Everything will look and work exactly as it did before, but your TextBoxes will automatically exhibit the new behaviour. Once you've built your project, the custom control will be added to the Toolbox, so you can add it to forms in the designer like any other control.
Note that, in order to access the designer code files, you need to select your project or an item within it in the Solution Explorer and click the Show All Files button. You can then expand the node for your form and open the designer code file.
Related
I have some simple code. It changes the BorderStyle property of a Label by right-clicking. Nothing fancy, but still. However, I have twenty labels. Is there a simpler way of doing this instead of "copy-paste" this code 20 times?
Private Sub Label1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles Label1.MouseDown
If e.Button = MouseButtons.Right Then
If Label1.BorderStyle = BorderStyle.None Then
Label1.BorderStyle = BorderStyle.FixedSingle
Else
Label1.BorderStyle = BorderStyle.None
End If
End If
End Sub
Private Sub Label2_MouseDown...
...
End Sub
You could either create a custom control which inherits from Label and has the behaviour you want, or you could write a handler which works out which control it is responding to from the sender parameter.
The latter, presented first here, is simpler for a one-off, but the former would be more re-usable, and you wouldn't have to maintain the list of Labels for the AddHandler.
Sub Label_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
Dim lbl = DirectCast(sender, Label)
If e.Button = MouseButtons.Right Then
If lbl.BorderStyle = BorderStyle.None Then
lbl.BorderStyle = BorderStyle.FixedSingle
Else
lbl.BorderStyle = BorderStyle.None
End If
End If
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each l In {Label1, Label2}
AddHandler l.MouseDown, AddressOf Label_MouseDown
Next
End Sub
The AddHandler line connects the MouseDown event of each of the Labels to the specified event handler. (You can add more than one event handler to an event, if needed.)
For a control (your very own custom one) derived from an existing control (a System.Windows.Forms.Label in this case), let's call it BorderedControl, you can follow the instructions at How to: Inherit from Existing Windows Forms Controls (it's too close to plagiarism to copy it to here), and then your code for the control might look like:
Public Class BorderedLabel
Inherits Label
Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
If e.Button = MouseButtons.Right Then
If Me.BorderStyle = BorderStyle.None Then
Me.BorderStyle = BorderStyle.FixedSingle
Else
Me.BorderStyle = BorderStyle.None
End If
End If
MyBase.OnMouseDown(e)
End Sub
Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
End Class
After you have built your project after adding that code, you will find a new control, named "BorderedLabel", in the ToolBox. You can drag that onto the form "design surface" and it will behave just like an ordinary Label except that it will have your BorderStyle-changing code incorporated automatically.
I'm working on a program wherein I have around 400 Text Boxes and I need to program an effect to make them show that they have focus. I can get the visual part down (Unless someone knows how to add a soft blue outline to a text box in VB), but I'm having trouble with creating GotFocus and LostFocus events that handle all of my Text Boxes at once. I've tried
Dim txtBox = Me.Controls.OfType(Of TextBox)
Private Sub TextBox_GotFocus(sender As Object, e As EventArgs) Handles txtBox.GotFocus
But I get a "Must have WithEvents variable" error which I don't quite understand how to fix. I've tried
Public Sub txtBoxGotFocusHandler(ByVal sender As Object,
ByVal e As System.EventArgs)
For Each txtBox As TextBox In Me.Controls 'References all text boxes in form
If txtBox.Focus = True Then
txtBox.BackColor = Color.Black
End If
Next
And I've tried a few other somewhat related things I've seen around the internet, but to no avail. Any help would be appreciated
You can make your app at runtime with any controls. You could query the layout of your app from SQL and from a simple change your app layout changes.
Private FocusRectangle As System.Drawing.Graphics
Private OldRectangle As System.Drawing.Graphics
Private MyTextBoxes As New List(Of TextBox)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
MyTextBoxes.Clear()
For xcount = 0 To 399
MyTextBoxes.Add(New TextBox)
With MyTextBoxes.Item(xcount)
.Name = "MyTextBoxes" & (xcount + 1).ToString
.Text = ""
.Location = New Point(0, 0)
.Size = New Size(50, 13)
.Visible = True
AddHandler .GotFocus, AddressOf MyTextBoxes_GotFocus
AddHandler .LostFocus, AddressOf MyTextBoxes_LostFocus
End With
Me.Controls.Add(MyTextBoxes.Item(xcount))
'add them to a panel....
'Panel1.Controls.add(MyTextBoxes.Item(xcount))
Next
End Sub
Sub MyTextBoxes_GotFocus(sender As Object, e As EventArgs)
Dim ThisTextBox As TextBox = DirectCast(sender, TextBox)
Dim xPen As New System.Drawing.Pen(Color.LightBlue)
FocusRectangle = Me.CreateGraphics()
FocusRectangle.DrawRectangle(xPen, ThisTextBox.Location.X - 1, ThisTextBox.Location.Y - 1, ThisTextBox.Size.Width + 1, ThisTextBox.Size.Height + 1)
OldRectangle = FocusRectangle
End Sub
Sub MyTextBoxes_LostFocus(sender As Object, e As EventArgs)
Dim ThisTextBox As TextBox = DirectCast(sender, TextBox)
OldRectangle.Dispose()
End Sub
Private Sub Form1_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
MyTextBoxes.Item(0).Focus()
End Sub
If you created your form with the Designer, the WithEvents is added for you automatically.
If you are declaring 400 text boxes as Private fields, you would declare them as Private WitheEvents txtBox As TextBox
If you're creating the text boxes programatically and adding them to a collection of textboxes or something, then you can't do WithEvents.
But all WithEvents does is allow you to add Handeles TextBox.SomeEvent to a function. Instead you can do this:
Dim txtBox As New TextBox
...
AddHandler txtBox.GotFocus, AddressOf txtBoxGotFocusHandler
Me.Controls.Add(txtBox)
I would like to ask if it is possible for VB.net applications to detect if a combobox has been changed without using SelectedIndexChange.
For Example my application has 4 comboboxes and this comboboxes was dynamically created from the user configuration. (the tool autocreates the comboboxes when the application was launched). Then once the application was launched, I want to run a SUB everytime those comboboxes was changed. Badly needed help. TIA
If you are creating controls dynamically, you should add the event handlers dynamically as well. There is nothing wrong with using the SelectedIndexChanged event.
You can test this by making a new project and pasting this code inside Public Class Form1.
Private myComboBox1 As ComboBox
Private myComboBox2 As ComboBox
Private Shared selectedIndexChanged As EventHandler =
Sub(sender As Object, e As EventArgs)
Dim myComboBox = DirectCast(sender, ComboBox)
' alert the user as to what was selected
MessageBox.Show(String.Format("{0} value: {1}, index: {2}",
myComboBox.Name, myComboBox.Text, myComboBox.SelectedIndex))
' you can do something different on each one by name in a case statement
Select Case myComboBox.Name
Case "myComboBox1"
' do something for 1
Case "myComboBox2"
' do something for 2
End Select
End Sub
Private Sub addHandlers()
AddHandler myComboBox1.SelectedIndexChanged, selectedIndexChanged
AddHandler myComboBox2.SelectedIndexChanged, selectedIndexChanged
End Sub
Private Sub removeHandlers()
RemoveHandler myComboBox1.SelectedIndexChanged, selectedIndexChanged
RemoveHandler myComboBox2.SelectedIndexChanged, selectedIndexChanged
End Sub
Form eventhandlers
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' dynamically generate combo boxes
myComboBox1 = New ComboBox() With {.Name = "myComboBox1",
.Left = 30,
.Top = 30}
myComboBox2 = New ComboBox() With {.Name = "myComboBox2",
.Left = 30,
.Top = 60}
' add some items
myComboBox1.Items.AddRange({1, 2, 3})
myComboBox2.Items.AddRange({"four", "five", "six"})
' add the combo boxes to the form
Me.Controls.Add(myComboBox1)
Me.Controls.Add(myComboBox2)
' add event handlers
addHandlers()
End Sub
Private Sub Form1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
removeHandlers()
End Sub
I have code that highlights the current textbox in focus in order to provide a visual cue to the user. My question is, if I had 10 forms with textboxes and I wanted to provide this same code to them all. Would I have to duplicate it or can I use a global method? If so, an example would be very helpful. Thanks.
The code is as follows.
Private Sub FocusChanged(ByVal sender As Object, ByVal e As EventArgs)
Dim txt As TextBox = sender
If txt.Focused Then
txt.Tag = txt.BackColor
txt.BackColor = Color.AliceBlue
Else
txt.BackColor = txt.Tag
End If
End Sub
Private Sub CreateAccount_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For Each ctrl As TextBox In Me.Controls.OfType(Of TextBox)()
AddHandler ctrl.GotFocus, AddressOf FocusChanged
AddHandler ctrl.LostFocus, AddressOf FocusChanged
ctrl.Tag = ctrl.BackColor
Next
End Sub
If you want to add this behavior to all TextBox controls, you're better off deriving your own class from the TextBox class, and override the OnGotFocus and OnLostFocus methods to set the properties accordingly.
Here's how:
Public Class MyTextBox
Inherits TextBox
Protected Overrides Sub OnGotFocus(e As System.EventArgs)
MyBase.OnGotFocus(e)
Me.Tag = Me.BackColor
Me.BackColor = Color.Aqua
End Sub
Protected Overrides Sub OnLostFocus(e As System.EventArgs)
MyBase.OnLostFocus(e)
Me.BackColor = Me.Tag
End Sub
End Class
EDIT: forgot to mention that after adding that class to your project, rebuild the solution, and if it compiles without errors, then your new TextBox class show show up in the VS ToolBox. You can then simply drag & drop onto your form just as any control.
Cheers
The form is an About Us form so has nothing on it only a text box and a OK button.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Me.Close()
End Sub
Here is how I'm opening the form:
Private Sub AboutAppStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AboutAppStripMenuItem.Click
Dim formAbout As New FormAbout()
formAbout.Show()
End Sub
Why won't the button close the form? I'm puzzled, I tried another button just in case with the same result.
UPDATE: I set a break point on Me.Close() and it isn't reaching it when I click the button, I created a new button and the same thing happened.
Thanks
I am betting the event handler for the button1_click event has been inadvertently removed.
Try double-clicking on the button in design time and see if it pulls you back to that same exact piece of code - or a new event handler definition.
If it's a new event handler definition - copy your code there and delete the first one.
There are other ways to manually add the event handler in the designer's code-behind - but maybe that's for a later progression.
From within VS click the "Show all files" button in solutions explorer. Grab us the code in .Designer.vb and paste it in here and we'll nail it down for you definitively.
Here's mine:
Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class Form1
Inherits System.Windows.Forms.Form
'Form overrides dispose to clean up the component list.
_
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
_
Private Sub InitializeComponent()
Me.Button1 = New System.Windows.Forms.Button
Me.SuspendLayout()
'
'Button1
'
Me.Button1.Location = New System.Drawing.Point(131, 91)
Me.Button1.Name = "Button1"
Me.Button1.Size = New System.Drawing.Size(133, 50)
Me.Button1.TabIndex = 0
Me.Button1.Text = "Button1"
Me.Button1.UseVisualStyleBackColor = True
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(292, 266)
Me.Controls.Add(Me.Button1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub
Friend WithEvents Button1 As System.Windows.Forms.Button
End Class
From MSDN:
Showing the control is equivalent to setting the Visible property to true. After the Show method is called, the Visible property returns a value of true until the Hide method is called.
when formabout is open
click on pause(break all) button in visual studio
click on step into in debug in visual studio
click on the close button in formabout
you will see which code is executed, if any
* edit *
another question
is formabout.enabled property is true?
I tested the following
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
Dim f As New Form2
f.Show()
End Sub
End Class
Public Class Form2
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
Me.Close()
End Sub
End Class
and did not have problems. As was suggested, re-create your button and code.
Add you Button Dynamically may solve the problem.
Place the following code in the load event of about Form.
Public Sub FormAbout_Load(ByVal sender as object,ByVal e as System.EventArgs)Handles Me.Load
Dim btn as new Button()
AddHandler btn.Click ,AddressOf _ClickToClose
End Sub
Private Sub _ClickToClose(ByVal sender as object,ByVal e as System.EventArgs)
Me.Close()
End Sub
Simple.
Select Project Properties from Solution Explorer.
Select Security tab to either uncheck "Enable ClickOnce..." or select "This is a full trust application".
Save the properties settings.
Solved.