Trapping WM_SETFOCUS in WindProc VB.NET - vb.net

I have a user control that inherits from a base user control class. On the user control that inherits this, I place a series of textboxes. At runtime, I need to know when each control gets focus and loses focus. To do this, I overrode WndProc in the base class, and am attempting to capture the messages there. The problem I'm having is that I never receive WM_SETFOCUS or WM_KILLFOCUS within the message loop.
This is the WndProc:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Select Case m.Msg
Case WM_SETFOCUS
Debug.WriteLine(m.ToString())
Case WM_KILLFOCUS
Debug.WriteLine(m.ToString())
Case Else
Debug.Print("OTHER: " + m.ToString())
End Select
MyBase.WndProc(m)
End Sub
I get a whole bunch of message for getting text and some other stuff, so I know that I'm getting there. It just never stops on WM_SETFOCUS or WM_KILLFOCUS.
What am I not doing correctly.

Quick example of wiring up all TextBoxes in the UserControl:
Public Class UserControl1
Private Sub UserControl1_Load(sender As Object, e As EventArgs) Handles Me.Load
WireTBs(Me)
End Sub
Private Sub WireTBs(ByVal cont As Control)
For Each ctl As Control In cont.Controls
If TypeOf ctl Is TextBox Then
Dim TB As TextBox = DirectCast(ctl, TextBox)
AddHandler TB.GotFocus, AddressOf TB_GotFocus
AddHandler TB.LostFocus, AddressOf TB_LostFocus
ElseIf ctl.HasChildren Then
WireTBs(ctl)
End If
Next
End Sub
Private Sub TB_GotFocus(sender As Object, e As EventArgs)
Dim TB As TextBox = DirectCast(sender, TextBox)
' ... do something with "TB" ...
Debug.Print("GotFocus: " & TB.Name)
End Sub
Private Sub TB_LostFocus(sender As Object, e As EventArgs)
Dim TB As TextBox = DirectCast(sender, TextBox)
' ... do something with "TB" ...
Debug.Print("LostFocus: " & TB.Name)
End Sub
End Class

Related

Clear focused textbox in multiple textboxes in vb.net using delete key

I want a good example of clearing focused textbox among multiple textboxes using delete key. Please help me providing vb.net code.
The public sub is as such :
Public Sub EmptyTxt(ByVal Frm As Form)
Dim Ctl As Control
For Each Ctl In Frm.Controls
'If TypeOf Ctl Is TextBox Then Ctl.Text = ""
Next
End Sub
Then I call this sub from delete keydown event. But it clears all textboxes rather than clearing the focused one.
There's an easier way to do that.
Simply assign all the textbox keyDown events to the same handler. In that handler, cast sender to a textbox and clear it.
Private Sub Form1_Load (sender As Object, e As EventArgs) Handles MyBase.Load
For Each tb As TextBox In Controls.OfType(Of TextBox)
AddHandler tb.KeyDown, AddressOf TbKeyDown
Next
End Sub
Private Sub TbKeyDown (sender As Object, e As KeyEventArgs)
Dim tb = CType(sender, TextBox)
If e.KeyCode = Keys.Delete Then
tb.Clear()
End If
End Sub

VB.Net AddHandler to entire User Control

Got a UserControl designed with several Labels and PictureBoxes.
Now I do integrate this UserControl via Controls.Add to a Panel where they get displayed the main Form1.
Now I like to raise an event once a UserControll is clicked or hovered.
If I do it via AddHandler taskItem.MouseClick, AddressOf meClick but its only triggered when I click the empty space of this Usercontrol and not on a label or PictureBox.
The goal is to use the Event to remove the clicked UserControl from the Label.
EDIT:
This is how my UserControl looks like:
Public Class Taks
Private Sub Taks_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each childControl As Control In Controls
AddHandler childControl.MouseClick, AddressOf Form1.meClick
Next
End Sub
Public Sub AddTasks(ByVal task_label As TaskLabels, ByVal show_seperator As Boolean, ByVal task_subject As String, ByVal task_message As String)
taskTitel.Text = task_subject
taskDesc.Text = task_message
If task_label = TaskLabels.General Then
taskImage.Image = My.Resources.Information_50px
End If
If task_label = TaskLabels.Important Then
taskImage.Image = My.Resources.Error_48px
End If
If task_label = TaskLabels.Critical Then
taskImage.Image = My.Resources.Box_Important_50px
End If
BunifuImageButton1.Hide()
End Sub
Enum TaskLabels
General = 0
Important = 1
Critical = 2
End Enum
End Class
And here I integrate the UserControl into a panel
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddTasks(Taks.TaskLabels.Critical, False, "Batterie Spannung", "low power")
AddTasks(Taks.TaskLabels.Important, False, "Wetter", "Das Wetter hat sich verschlechtert, Wind > 15km/h")
AddTasks(Taks.TaskLabels.General, False, "Server", "Auslastung liegt bei 12%")
AddTasks(Taks.TaskLabels.Important, False, "Temperature", "Temperatur der Proben im Kritischen Bereich")
End Sub
Sub AddTasks(ByVal taksLabels As Taks.TaskLabels, ByVal task_sep As Boolean, ByVal taskTitle As String, ByVal TaskDesc As String, Optional ByVal toFront As Boolean = False)
Dim taskItem As New Taks
taskItem.AddTasks(taksLabels, task_sep, taskTitle, TaskDesc)
taskItem.Dock = DockStyle.Top
AddHandler taskItem.MouseClick, AddressOf meClick
taskItem.Cursor = Cursors.Hand
Panel1.Controls.Add(taskItem)
End Sub
Public Sub meClick(sender As Object, e As MouseEventArgs)
If MessageBox.Show("delete Event?", "Question", MessageBoxButtons.YesNo) = Windows.Forms.DialogResult.Yes Then
Panel1.Controls.Remove(sender)
End If
BunifuVScrollBar1.Maximum = Panel1.Height
End Sub
End Class
That's how events work. It's just like how a form doesn't raise a Click event when you click a Button on it. If you want the UC to raise a MouseClick event when a child control is clicked on then you need to handle the event of the child control internally and then raise the UC's event yourself. E.g.
Public Class UserControl1
Private Sub UserControl1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each childControl As Control In Controls
'Filter specific control types if desired.
If TypeOf childControl Is Label OrElse TypeOf childControl Is Panel Then
AddHandler childControl.MouseClick, AddressOf ChildControls_MouseClick
End If
Next
End Sub
Private Sub ChildControls_MouseClick(sender As Object, e As MouseEventArgs)
Dim childControl = DirectCast(sender, Control)
'Translate location on child control to location on user control.
Dim translatedLocation = PointToClient(childControl.PointToScreen(e.Location))
Dim args As New MouseEventArgs(e.Button,
e.Clicks,
translatedLocation.X,
translatedLocation.Y,
e.Delta)
'Raise the event of the user control.
OnMouseClick(args)
End Sub
End Class

Visual Indication of Focus and Adding Click Event To all TextBoxes

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)

Iterate Through Devexpres TextEdit Controls in VB.NET

Could someone help iterating through DevExpress TextEdit controls within an XTRAFORM in vb.net?
What I am actually trying to do is to intercept any value changes at FormClosing event by using EditValue and OldEditValue properties.
I meight need to tell that my controls are contained in XtraTab and XtraPanel Containers.
the following is what I tried:
Public Function TextEditChangesOccured(frm As XtraForm) As Boolean
Dim result As Boolean
For Each ctrl As BaseEdit In frm.Controls
If TypeOf ctrl Is TextEdit Then
If ctrl.EditValue <> ctrl.OldEditValue Then
result = True
Else
result = False
End If
End If
Next
Return result
End Function
Private Sub MyXtraForm_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
If TextEditChangesOccured(Me) Then
DevExpress.XtraEditors.XtraMessageBox.Show("Changes have occured!", My.Application.Info.AssemblyName, MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
End Sub
but it says unable to cast XtraTab control to TextEdit control.
Your help will be much appreciated.
To make your code works just change your code snippet as follows:
Public Function TextEditChangesOccured(container As Control) As Boolean
Dim result As Boolean
For Each ctrl As Control In container.Controls
Dim bEdit As BaseEdit = TryCast(ctrl, BaseEdit)
If bEdit IsNot Nothing Then
Dim tEdit As TextEdit = TryCast(ctrl, TextEdit)
If tEdit IsNot Nothing Then
result = result Or (bEdit.EditValue <> bEdit.OldEditValue)
End If
Else
result = result Or TextEditChangesOccured(ctrl)
End If
Next
Return result
End Function
To detect changes for all the editors within a Form use the following approach:
Partial Public Class Form1
Inherits Form
Public Sub New()
InitializeComponent()
SubscribeTextEditValueChanged(Me)
End Sub
Private Sub SubscribeTextEditValueChanged(ByVal container As Control)
For Each ctrl As Control In container.Controls
Dim tEdit As TextEdit = TryCast(ctrl, TextEdit)
If tEdit IsNot Nothing Then
AddHandler tEdit.EditValueChanged, AddressOf tEdit_EditValueChanged
Else
SubscribeTextEditValueChanged(ctrl)
End If
Next ctrl
End Sub
Private IsEditValueChanged As Boolean
Private Sub tEdit_EditValueChanged(ByVal sender As Object, ByVal e As EventArgs)
IsEditValueChanged = True
End Sub
Protected Overrides Sub OnClosing(ByVal e As CancelEventArgs)
If IsEditValueChanged Then
' do some stuff
End If
MyBase.OnClosing(e)
End Sub
End Class

Using handlers across multiple forms?

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