VB.Net AddHandler to entire User Control - vb.net

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

Related

How to trigger a gotfocus datagrid combobox event while grid is readonly?

I have a datagridview and I'm trying to get the gotfocus event for my comboboxcells to still call despite the datagrid being on readonly.
This gotfocus event changes the colour of every combobox with a similar value (including itself) and I would like to it to still call while on readonly (the datagridview comboboxes can still be selected/highlighted while on readonly but it is not called(?))
Below is the basics of how I am currently handling the events (for some reason this shortened version makes multiple event calls at an exponential rate & also requires three clicks to trigger... I'm not sure why it does this but my full project works fine in this regard)
Public Class Form1
Private Sub cell_gotfocus(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles DataGridView1.EditingControlShowing
Dim CurrentCombo = TryCast(e.Control, ComboBox)
If Not CurrentCombo Is Nothing Then
RemoveHandler CurrentCombo.GotFocus, AddressOf Combo_Focus 'remove event handler so we don't accumulate multiples
AddHandler CurrentCombo.GotFocus, AddressOf Combo_Focus 'add eventhandler
End If
End Sub
Private Sub Combo_Focus()
Console.WriteLine("Got Focus")
Console.beep
End Sub
Private Sub Make_Readonly_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Make_Readonly.Click
DataGridView1.Rows(0).ReadOnly = True 'toggle readonly
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For y As Integer = 1 To 4 'add extra columns into datagrid
Dim cmb As New DataGridViewComboBoxColumn
cmb.HeaderText = "c" & DataGridView1.Columns.Count
cmb.Name = "c" & DataGridView1.Columns.Count
cmb.FlatStyle = FlatStyle.Flat
DataGridView1.Columns.Add(cmb)
Next
End Sub
End Class

Overriding a derived Event

I want to "override" an Event from a derived class - for example from a Forms-Control.
My actual state is, that the overriding (performed by the Command "Shadows") is working when I use the Handler of this Control directly.
Is the Control a member of a Collection it is only working with such Events which I have created by myself - if I try to use the overridden Event it isn't working. I suppose that the Collection uses the Event from the Base-Class.
Is that possible ?
And if "Yes" - what could I do ?
Code-Snippets from the described "Problem" :
This part collects the Event-Handler inside the Custom Control :
Private KalenderElemente As New Collection
Private Sub CreateElements()
KalenderElemente.Clear()
For i As Integer = 1 To 42
Dim myKalenderTag As New PP_Monatskalender_Tag
myKalenderTag.Name = "Tag_" + i.ToString("00")
myKalenderTag.ForeColor = my_ForeColor_Days
myKalenderTag.BackColor = my_BackColor_Days
myKalenderTag.Parent = Me
AddHandler myKalenderTag.Click, AddressOf KalenderTag_Click
AddHandler myKalenderTag.MouseMove, AddressOf KalenderTag_MouseMove
AddHandler myKalenderTag.MouseEnter, AddressOf KalenderTag_MouseEnter
AddHandler myKalenderTag.MouseLeave, AddressOf KalenderTag_MouseLeave
KalenderElemente.Add(myKalenderTag)
Next
End Sub
Private Sub Kalender_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles MyBase.MouseMove
If Not KalenderElemente.Item(0).Visible Then
KalenderElemente.Item(0).DatumsTag = 0
RaiseEvent MouseMove(KalenderElemente.Item(0), e)
Else
KalenderElemente.Item(41).DatumsTag = 0
RaiseEvent MouseMove(KalenderElemente.Item(41), e)
End If
End Sub
Private Sub KalenderTag_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
RaiseEvent MouseMove(sender, e)
End Sub
Shadows Event MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
Private Sub KalenderTag_MouseEnter(ByVal sender As Object, ByVal e As EventArgs)
RaiseEvent MouseEnter(sender, e)
End Sub
Shadows Event MouseEnter(ByVal sender As Object, ByVal e As EventArgs)
Private Sub KalenderTag_MouseLeave(ByVal sender As Object, ByVal e As EventArgs)
RaiseEvent MouseLeave(sender, e)
End Sub
Shadows Event MouseLeave(ByVal sender As Object, ByVal e As EventArgs)
Now each of the internal Controls deliver it's Mouse-Event to outside.
If I put it on a Form and write a script which takes the Event I could see that all works fine (and as expected).
In the following you see the part of the collection which should manage this Control (and others) :
Public Class MessageDefinition
Public WithEvents Control As Control
Public HeaderText As String
Public MessageText As String
Public DisplayShadow As Boolean
Public ToolTipLocation As ToolTipLocationDefintion
Public Location As Point
End Class
Public Class Message_Collection
Inherits CollectionBase
Public Shadows Sub Clear()
Dim myItem As MessageDefinition
For i As Integer = 1 To List.Count
myItem = List.Item(i - 1)
RemoveHandler myItem.Control.MouseEnter, AddressOf Item_MouseEnter
RemoveHandler myItem.Control.MouseMove, AddressOf Item_MouseMove
RemoveHandler myItem.Control.MouseLeave, AddressOf Item_MouseLeave
Next
List.Clear()
End Sub
Overrides Function ToString() As String
Return "[...]"
End Function
Public Sub Dispose()
Clear()
End Sub
' ================================
Public Sub SetMessage(item As MessageDefinition)
Dim myItem As MessageDefinition
For i As Integer = 1 To List.Count
myItem = List.Item(i - 1)
If myItem.Control.GetType Is item.Control.GetType _
AndAlso myItem.Control.Name = item.Control.Name Then
'List.Item(i - 1) = item
'RaiseEvent MouseEnter(item, System.EventArgs.Empty)
Exit Sub
End If
Next
AddHandler item.Control.MouseEnter, AddressOf Item_MouseEnter
AddHandler item.Control.MouseMove, AddressOf Item_MouseMove
AddHandler item.Control.MouseLeave, AddressOf Item_MouseLeave
List.Add(item)
RaiseEvent MouseEnter(item, System.EventArgs.Empty)
End Sub
Private Sub Item_MouseEnter(sender As Object, e As System.EventArgs)
Dim myItem As MessageDefinition
Dim mySender As Control = sender
For i As Integer = 1 To List.Count
myItem = List.Item(i - 1)
If myItem.Control Is mySender Then
RaiseEvent MouseEnter(myItem, e)
Exit Sub
End If
Next
End Sub
Private Sub Item_MouseMove(sender As Object, e As System.EventArgs)
Dim myItem As MessageDefinition
Dim mySender As Control = sender
For i As Integer = 1 To List.Count
myItem = List.Item(i - 1)
If myItem.Control Is mySender Then
RaiseEvent MouseMove(myItem, e)
Exit Sub
End If
Next
End Sub
Private Sub Item_MouseLeave(sender As Object, e As System.EventArgs)
Dim myItem As MessageDefinition
Dim mySender As Control = sender
For i As Integer = 1 To List.Count
myItem = List.Item(i - 1)
If myItem.Control Is mySender Then
RaiseEvent MouseLeave(myItem, e)
Exit Sub
End If
Next
End Sub
Public Event MouseEnter(sender As Object, e As System.EventArgs)
Public Event MouseMove(sender As Object, e As System.EventArgs)
Public Event MouseLeave(sender As Object, e As System.EventArgs)
End Class
As described (on Top) the catched Events are fired with "Standard"-Controls but not with the "Customized" Control.
If I change it and build up my own Events (with different names), which are not shadowing the Events from the derived control, it is also working as expected.
You don't override events in .NET - you can only override inherited event handlers, if any.
The event pattern in .NET is to create a public event in the base class and a protected virtual (VB Protected Overridable) method that raises that event and that can be overridden by a derived class. This method should be named OnEventName.
The Windows Forms controls follow this pattern, so to e.g. override when the Click event happens, you override the OnClick method:
Public Class MyTextBox
Inherits TextBox
Protected Overrides Sub OnClick(ByVal e As System.EventArgs)
If SomeCondition() Then
MyBase.OnClick(e)
Else
Return 'Do not click
End If
End Sub
End Class
Obviously you can fiddle with the e argument as well.

VB 2010 Form Show

i currently have multiple forms (around 30 forms) and i am switching between forms. The Main form (Form1) has 29 buttons and each button will take me to the respective form number (example: button3 = form3, button20=form20, etc).
I understand that I can use the code:
me.hide
form1.show
I want a method to pass the form name dynamically, something along the lines of:
me.controls(FormName).show
Is this possible?
Create a new project with three forms (Form1, Form2, and Form3). Put two buttons on Form1 (named Button2 and Button3), then place the following source code in Form1:
Option Strict On
Public Class Form1
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Call FormFromButton(DirectCast(sender, Button))
End Sub
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Call FormFromButton(DirectCast(sender, Button))
End Sub
Public Sub FormFromButton(btn As Button)
Dim i As Integer = CInt(btn.Name.Substring(6)) 'Get number after "button" (6 characters)
Dim f As Form = GetForm("Form" & i.ToString)
f.Show()
f.Activate()
End Sub
Public Function GetForm(formClassName As String) As Form
'see if it is already instanced
For Each f As Form In My.Application.OpenForms
If f.GetType.Name = formClassName Then Return f
Next f
'create new instance
Dim strFullName As String = Me.GetType.Namespace & "." & formClassName
Dim o As Object = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(strFullName)
Dim frm As Form = DirectCast(o, Form)
Return frm
End Function
End Class
Myself created 4 forms one is parent another 3(Form3,Form4,Form5) is child and i was created 3 buttons in parent form and that button Text is Form3,Form4,Form5
Imports System
Imports System.Reflection
Public Class Form2
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each ctrl As Control In Me.Controls
If TypeOf ctrl Is Button Then
Dim btn As Button
btn = DirectCast(ctrl, Button)
AddHandler btn.Click, AddressOf Me.buttonclick
End If
Next
End Sub
Private Sub buttonclick(sender As Object, e As EventArgs)
Dim frmname As Button = DirectCast(sender, Button)
Dim frmAssembly As Assembly = Assembly.LoadFile(Application.ExecutablePath)
For Each type As Type In frmAssembly.GetTypes
If type.BaseType = GetType(Form) Then
If (type.Name = frmname.Text) Then
Dim frmshow As Form = DirectCast(frmAssembly.CreateInstance(type.ToString()), Form)
For Each frm As Form In Me.MdiChildren
frm.Close()
Next
frmshow.Show()
End If
End If
Next
End Sub
End Class
Private Sub ButtonClick(ByVal sender As Object, e As System.EventArgs)
Dim btn As Button = DirectCast(sender, Button)
Dim formname As String = "form" & btn.Name(btn.Name.Length - 1)
Dim frm As Form = GetForm(formname)
frm.Show()
End Sub
Private Function GetForm(ByVal Formname As String) As Form
Dim t As Type = Type.GetType(Formname) ', True, True)
If t Is Nothing Then
Dim Fullname As String = Application.ProductName & "." & Formname
t = Type.GetType(Fullname, True, True)
End If
Return CType(Activator.CreateInstance(t), Form)
End Function
Private Sub AddHandlers()
AddHandler Button1.Click, AddressOf ButtonClick
AddHandler Button2.Click, AddressOf ButtonClick
AddHandler Button3.Click, AddressOf ButtonClick
AddHandler Button4.Click, AddressOf ButtonClick
End Sub
Private Sub RemoveHandlers()
RemoveHandler Button1.Click, AddressOf ButtonClick
RemoveHandler Button2.Click, AddressOf ButtonClick
RemoveHandler Button3.Click, AddressOf ButtonClick
RemoveHandler Button4.Click, AddressOf ButtonClick
End Sub
Private Sub Form2_Activated(sender As Object, e As System.EventArgs) Handles Me.Activated
AddHandlers()
End Sub
Private Sub Form2_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
RemoveHandlers()
End Sub

How to make a click event for runtime created controls in Visual Basic 2010?

I added some controls to my form at runtime and I need them to call a function when clicked. I don't know how many controls will be added but they all need to run the same function. How would I define the event? Can I define events based on all controls of a given class?
A simple example :
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' creating control
Dim btn1 As Button = New Button()
Dim btn2 As Button = New Button()
btn1.Parent = Me
btn1.Name = "btn1"
btn1.Top = 10
btn1.Text = "Btn1"
btn2.Parent = Me
btn2.Name = "btn2"
btn2.Top = 50
btn2.Text = "Btn2"
'adding handler for click event
AddHandler btn1.Click, AddressOf HandleDynamicButtonClick
AddHandler btn2.Click, AddressOf HandleDynamicButtonClick
End Sub
Private Sub HandleDynamicButtonClick(ByVal sender As Object, ByVal e As EventArgs)
Dim btn As Button = DirectCast(sender, Button)
If btn.Name = "btn1" Then
MessageBox.Show("Btn1 clicked")
ElseIf btn.Name = "btn2" Then
MessageBox.Show("Btn2 Clicked")
End If
End Sub
End Class
Simply:
AddHandler Control.Event, AddressOf MethodExecuting
For example:
AddHandler Button1.Click, AddressOf ClickMethod

Making combobox visible when it is disabled

I am disabling combobox in VB.net.
But in disable mode it not visible properly.
I tried changing both BackColor and ForeColor but it is not working.
Code :
cmbbox.BackColor = Color.FromName("Window")
or
cmbbox.ForeColor = Color.FromName("Window")
Please help
Dear Adam:
I am making my component enable false.But I want to make it viewable.You can reffer the link.This is what exacly I want but in VB.Net : A combobox that looks decent when it is disabled
To achieve disabling combobox without fading it, first change the dropdown style of the combobox to DropDownList, Then tweak with the events to achieve the goal.
Here is a piece of code by which you can achieve the same:
Public Class Form1
Dim selectindex As Integer
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
ComboBox1.Items.Add("1")
ComboBox1.Items.Add("2")
ComboBox1.Items.Add("3")
ComboBox1.Items.Add("4")
selectindex = 3
ComboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList
ComboBox1.SelectedIndex = selectindex
End Sub
Private Sub ComboBox1_SelectionChangeCommitted(ByVal sender As Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectionChangeCommitted
ComboBox1.SelectedIndex = selectindex
End Sub
End Class
Create anew form Form1 and add a combobox to the form, then add the above code to get a readonly combobox.
Have a look at this thread which has a solution for a readonly combobox and the code is all VB.NET.
A version of their code is as follows. You'll need to but it inside a class of your own which inherits System.Windows.Forms.ComboBox
Private _ReadOnly As Boolean = False
Public Property [ReadOnly]() As Boolean
Get
Return _ReadOnly
End Get
Set(ByVal Value As Boolean)
_ReadOnly = Value
End Set
End Property
Public Overrides Function PreProcessMessage(ByRef msg As Message) As Boolean
'Prevent keyboard entry if control is ReadOnly
If _ReadOnly = True Then
'Check if its a keydown message
If msg.Msg = &H100 Then
'Get the key that was pressed
Dim key As Int32 = msg.WParam.ToInt32
'Ignore navigation keys
If key = Keys.Tab Or key = Keys.Left Or key = Keys.Right Then
'Do nothing
Else
Return True
End If
End If
End If
'Call base method so delegates receive event
Return MyBase.PreProcessMessage(msg)
End Function
Protected Overrides Sub WndProc(ByRef m As Message)
'Prevent list displaying if ReadOnly
If _ReadOnly = True Then
If m.Msg = &H201 OrElse m.Msg = &H203 Then
Return
End If
End If
'Call base method so delegates receive event
MyBase.WndProc(m)
End Sub
I've been looking for the same not long ago and ended up doing the following. You may not like it, but i'll share it in case. I am using TableLayoutPanel to arrange my controls on the form and then i am swapping the positions of the desired controls.
For example I've created the following Items:
Form1 Design
TableLayoutPanel1 (two columns, three rows)
TextBox1 Read-only = True, BackColor = White
ComboBox1 Visible = False, DropDownStyle = DropDownList, FlatStyle = Popup
Button1 (named it to Change)
Button2 (named it to Done) -> Visible = False
Runtime - Screenshots
Here is my code:
Public Class Form1
Private Sub SwapControls(tlp As TableLayoutPanel, ctr1 As Control, ctr2 As Control)
Dim ctl1pos As TableLayoutPanelCellPosition = tlp.GetPositionFromControl(ctr1)
ctr1.Visible = False
tlp.SetCellPosition(ctr1, tlp.GetPositionFromControl(ctr2))
ctr2.Visible = True
tlp.SetCellPosition(ctr2, ctl1pos)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
SwapControls(TableLayoutPanel1, TextBox1, ComboBox1)
SwapControls(TableLayoutPanel1, Button1, Button2)
Label1.Select()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
SwapControls(TableLayoutPanel1, ComboBox1, TextBox1)
SwapControls(TableLayoutPanel1, Button2, Button1)
Label1.Select()
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Label1.Select()
ComboBox1.SelectedIndex = 0
TextBox1.Text = ComboBox1.SelectedItem
End Sub
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
TextBox1.Text = ComboBox1.SelectedItem
End Sub
End Class