Set HandCursor for all ToolStripButton by Linq, Extension, Delegates, Lambda Expression and Anonymous Action.
- 1. Extension function with Linq.
- 2. Use Lambda Expression to call Delegates in ForEach by AddressOF statement.
- 3. Use one Named function as Action to different type of controls for call delegates.
- 4. Use Anonymous Action instead named function.
1. Extension function with Linq.
This is very simple future, but for write similar code free, need to deep understanding all Visual Basic opportunity. Firstly, this is two simple extension function to obtain all control by type or name.
110: <Extension()>
111: Public Function FindRecusriveByName(ByVal control As Control, ControlName As String) As IEnumerable(Of Control)
112: Dim controls = control.Controls.Cast(Of Control)()
113: Return controls.SelectMany(Function(ctrl) FindRecusriveByName(ctrl, ControlName)).Concat(controls).Where(Function(c) c.Name = ControlName)
114: End Function
115:
116: <Extension()>
117: Public Function FindRecusriveByType(ByVal control As Control, ByVal type As Type) As IEnumerable(Of Control)
118: Dim controls = control.Controls.Cast(Of Control)()
119: Return controls.SelectMany(Function(ctrl) FindRecusriveByType(ctrl, type)).Concat(controls).Where(Function(c) c.[GetType]() = type)
120: End Function
121:
122:
123: End Module
I use they in different rules, for example set a custom format of DatagridView.
But code below is more sophisticated and interesting, because it use one Lambda expression including to another.
2. Use Lambda Expression to call Delegates in ForEach by AddressOF statement.
In the internal part I call EventHandler delegates ToolStripButton_MouseEnter and ToolStripButton_MouseLeave by keyword AddressOF. More details about delegates (Static/Dynamic declaration, AddressOf/RaiseEvent/AddHandler/WithEvents/Handles statement, SingleCast/MultiCast/InvocationList, Invoke/BeginInvoke/DynamicInvoke/AsyncInvoke, Automatically instantiate) please see in this my article - Events/Delegates in VB.NET
41: Dim savedCursor As Windows.Forms.Cursor
42:
43: Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
44:
45: Me.FindRecusriveByType(GetType(ToolStrip)).ToList.ForEach(Sub(Y)
46: Dim ToolStrip = CType(Y, ToolStrip)
47: ToolStrip.Items.OfType(Of ToolStripButton).ToList.ForEach(Sub(X)
48: Debug.Print(X.Name)
49: AddHandler X.MouseEnter, AddressOf ToolStripButton_MouseEnter
50: AddHandler X.MouseLeave, AddressOf ToolStripButton_MouseLeave
51: End Sub)
52: End Sub)
53: Me.FindRecusriveByType(GetType(StatusStrip)).ToList.ForEach(Sub(Y)
54: Dim ToolStrip = CType(Y, StatusStrip)
55: ToolStrip.Items.OfType(Of ToolStripButton).ToList.ForEach(Sub(X)
56: Debug.Print(X.Name)
57: AddHandler X.MouseEnter, AddressOf ToolStripButton_MouseEnter
58: AddHandler X.MouseLeave, AddressOf ToolStripButton_MouseLeave
59: End Sub)
60: End Sub)
...
76: Private Sub ToolStripButton_MouseEnter(ByVal sender As Object, ByVal e As System.EventArgs)
77: If savedCursor Is Nothing Then
78: savedCursor = Me.Cursor
79: Me.Cursor = Cursors.Hand
80: End If
81: End Sub
82:
83: Private Sub ToolStripButton_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs)
84: Me.Cursor = savedCursor
85: savedCursor = Nothing
86: End Sub
87:
3. Use one Named function as Action to different type of controls for call delegates.
And this is next step to simplify code, it use characteristic of StatusStrip class, because it inherit from ToolStrip, we can use one Action to both type on container.
Pay attention than both of syntax (45 and 46 line) is equal.
41: Dim savedCursor As Windows.Forms.Cursor
42:
43: Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
44:
45: Me.FindRecusriveByType(GetType(ToolStrip)).ToList.ForEach(New Action(Of Control)(AddressOf SetCursor))
46: Me.FindRecusriveByType(GetType(StatusStrip)).ToList.ForEach(AddressOf SetCursor)
...
63: Sub SetCursor(Y)
64: Dim ToolStrip = CType(Y, ToolStrip)
65: ToolStrip.Items.OfType(Of ToolStripButton).ToList.ForEach(Sub(X)
66: Debug.Print(X.Name)
67: AddHandler X.MouseEnter, AddressOf ToolStripButton_MouseEnter
68: AddHandler X.MouseLeave, AddressOf ToolStripButton_MouseLeave
69: End Sub)
70: End Sub
71:
4. Use Anonymous Action instead named function.
And finally you can see my last version of implementation the same future with anonymous Action (one of both type).
41: Dim savedCursor As Windows.Forms.Cursor
42:
43: Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
44:
45: Me.FindRecusriveByType(GetType(ToolStrip)).ToList.ForEach(SetCursor)
46: Me.FindRecusriveByType(GetType(StatusStrip)).ToList.ForEach(SetCursor)
47:
...
63: Dim SetCursor As Action(Of Control) = Sub(Y As Control)
64: Dim ToolStrip = CType(Y, ToolStrip)
65: ToolStrip.Items.OfType(Of ToolStripButton).ToList.ForEach(Sub(X)
66: Debug.Print(X.Name)
67: AddHandler X.MouseEnter, AddressOf ToolStripButton_MouseEnter
68: AddHandler X.MouseLeave, AddressOf ToolStripButton_MouseLeave
69: End Sub)
70: End Sub
|