Mainform VB.Net:
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Partial Class Form1
Inherits System.Windows.Forms.Form
'Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()>
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.
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
Me.tsBasket = New System.Windows.Forms.ToolStrip()
Me.tsiFruit = New System.Windows.Forms.ToolStripDropDownButton()
Me.tsBasket.SuspendLayout()
Me.SuspendLayout()
'
'tsBasket
'
Me.tsBasket.Dock = System.Windows.Forms.DockStyle.None
Me.tsBasket.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden
Me.tsBasket.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.tsiFruit})
Me.tsBasket.Location = New System.Drawing.Point(355, 213)
Me.tsBasket.Name = "tsBasket"
Me.tsBasket.Size = New System.Drawing.Size(121, 25)
Me.tsBasket.TabIndex = 5
'
'tsiFruit
'
Me.tsiFruit.ImageTransparentColor = System.Drawing.Color.Magenta
Me.tsiFruit.Name = "tsiFruit"
Me.tsiFruit.Size = New System.Drawing.Size(87, 22)
Me.tsiFruit.Text = "add fruit"
'
'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.tsBasket)
Me.Name = "Form1"
Me.Text = "Form1"
Me.tsBasket.ResumeLayout(False)
Me.tsBasket.PerformLayout()
Me.ResumeLayout(False)
Me.PerformLayout()
End Sub
Friend WithEvents tsBasket As ToolStrip
Friend WithEvents tsiFruit As ToolStripDropDownButton
End Class
Form Load:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim men As New TestTool()
men.Text = "showmeplease"
men.Image = Nothing
men.NewProperty = "BO"
Dim men2 As New TestTool()
men2.Text = "showmeplease2"
men2.Image = Nothing
men2.NewProperty = "BO2"
tsiFruit.DropDownItems.Add(men)
tsiFruit.DropDownItems.Add(men2)
AddHandler men.Click, AddressOf tsiType_Click
AddHandler men2.Click, AddressOf tsiType_Click
End Sub
Private Sub tsiType_Click(sender As System.Object, e As System.EventArgs)
Dim MenuItem As TestTool = DirectCast(sender, TestTool)
MessageBox.Show(MenuItem.NewProperty & " " & MenuItem.Text)
End Sub
Custom class:
Public Class TestTool
Inherits ToolStripItem
Private newPropertyValue As String
Public Property NewProperty() As String
Get
Return newPropertyValue
End Get
Set(ByVal value As String)
newPropertyValue = value
End Set
End Property
Sub New()
' This call is required by the designer.
' InitializeComponent()
End Sub
End Class
On my custom class/Usercontrol I am getting :
The designer must create an instance of type 'System.Windows.Forms.ToolStripItem' but it cannot because the type is declared as abstract. and I am not seeing the text appear in the menu items, but the click event works fine.
Is this the correct way to extend(Inherit using OO) a ToolMenuStrip so that I can have a Display value and a Member value, I want to be able to store an object without using .Tag.
Edit:
I am getting when trying to have nested menus:
System.InvalidCastException: 'Unable to cast object of type 'System.Windows.Forms.ToolStripMenuItem' to type 'WindowsApp1.TestTool'.'
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim men As New TestTool()
men.Text = "showmeplease"
men.Image = Nothing
men.NewProperty = "BO"
Dim men2 As New TestTool()
men2.Text = "showmeplease2"
men2.Image = Nothing
men2.NewProperty = "BO2"
tsiFruit.DropDownItems.Add(men)
tsiFruit.DropDownItems.Add(men2)
Dim TypeMenuItem As TestTool = men.DropDownItems.Add("hh")
For Each mInfo As String In Moreinfo
TypeMenuItem.DropDownItems.Add(mInfo, Nothing, AddressOf tsiType_Click)
Next
AddHandler men.Click, AddressOf tsiType_Click
AddHandler men2.Click, AddressOf tsiType_Click
End Sub
Private p_Moreinfo As List(Of String)
Public Property Moreinfo() As List(Of String)
Get
Dim test As New List(Of String)
test.Add("A")
test.Add("B")
Return test
End Get
Set(ByVal value As List(Of String))
p_Moreinfo = value
End Set
End Property
If you enable the Option Strict check (you should), you will find an error with the line below in the Form1_Load event:
' Error: Option Strict On disallows implicit conversions from ToolStrinpItem
' to TestTool.
Dim TypeMenuItem As TestTool = men.DropDownItems.Add("hh")
Because the .DropDownItems.Add(String) overload returns a ToolStripItem and not an object of type TestTool. The .DropDownItems don't inherit the type of the owner item.
' Compiles.
Dim TypeMenuItem As ToolStripItem = men.DropDownItems.Add("hh")
' Compiles.
Dim TypeMenuItem As ToolStripMenuItem = DirectCast(men.DropDownItems.Add("hh"), ToolStripMenuItem)
' Throws System.InvalidCastException.
Dim TypeMenuItem As TestTool = DirectCast(men.DropDownItems.Add("hh"), TestTool)
So, the code in Load event should be like:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim men As New TestTool With {
.Text = "showmeplease",
.NewProperty = "BO"
}
Dim men2 As New TestTool With {
.Text = "showmeplease2",
.NewProperty = "BO2"
}
tsiFruit.DropDownItems.Add(men)
tsiFruit.DropDownItems.Add(men2)
Dim TypeMenuItem As New TestTool() With {.NewProperty = "hh", .Text = "SomeText"}
men.DropDownItems.Add(TypeMenuItem)
For Each mInfo As String In Moreinfo
Dim item = New TestTool With {.NewProperty = mInfo, .Text = "SomeText"}
AddHandler item.Click, AddressOf tsiType_Click
TypeMenuItem.DropDownItems.Add(item)
Next
AddHandler men.Click, AddressOf tsiType_Click
AddHandler men2.Click, AddressOf tsiType_Click
End Sub
Likewise, to avoid throwing exceptions in the tsiType_Click event, just in case:
Private Sub tsiType_Click(sender As Object, e As EventArgs)
Dim item = TryCast(sender, TestTool)
If item IsNot Nothing Then
MessageBox.Show($"{item.NewProperty} {item.Text}")
Else
MessageBox.Show(DirectCast(sender, ToolStripItem).Text)
End If
End Sub
I believe you have modified the TestTool class as #jmcilhinney commented to something like:
Public Class TestTool
Inherits ToolStripMenuItem
Sub New()
MyBase.New
End Sub
Public Property NewProperty As String
End Class
Like the title above, I am trying to display the focus box on the subitem / cell that is clicked.
To get the subitem / cell that is clicked I use the following code:
Private Sub LV_MouseClick(sender As Object, e As MouseEventArgs) Handles LV.MouseClick
Info = LV.HitTest(e.Location)
ClickedColumnLV = Info.Item.SubItems.IndexOf(Info.SubItem)
ClickedRowLV = Info.Item.Index
If e.Button = MouseButtons.Right Then
If LV.FocusedItem.Bounds.Contains(e.Location) Then
CMenu.Show(Cursor.Position)
End If
End If
End Sub
At this point i have Row Index (ClickedRowLV) and Column Index (ClickedColumnLV)
Now I'am trying show focus on that clicked subitem/cell.
How can I do that?
EDIT :
Just to make sure that I didn't click the wrong item. So I want to have a focus rect or a sign if the sub-item is clicked.
Row must be full row select but at subitem /cell there is focus rect inside or outide. For example, please see the picture :
Not quite sure whether you mean something like:
If that is true, then you can handle the MouseDown event of the ListView control as follows:
Private Sub LV_MouseDown(sender As Object, e As MouseEventArgs) Handles LV.MouseDown
Dim selColor = SystemColors.Highlight
Dim item = LV.Items.Cast(Of ListViewItem).
Where(Function(x) x.BackColor.Equals(selColor) OrElse
x.SubItems.Cast(Of ListViewItem.ListViewSubItem).
Any(Function(y) y.BackColor.Equals(selColor))).FirstOrDefault
If item IsNot Nothing Then
item.BackColor = SystemColors.Window
item.ForeColor = SystemColors.WindowText
For Each subItem In item.SubItems.Cast(Of ListViewItem.ListViewSubItem)
subItem.BackColor = SystemColors.Window
subItem.ForeColor = SystemColors.WindowText
Next
End If
Dim ht = LV.HitTest(e.Location)
If ht.SubItem IsNot Nothing Then
ht.Item.UseItemStyleForSubItems = False
ht.SubItem.BackColor = selColor
ht.SubItem.ForeColor = SystemColors.Window
End If
End Sub
Of course this won't work if the FullRowSelect property is enabled.
Edit: Custom ListView
Following up on your comment and update, I don't know any easy way to achieve that. I think you need to create a custom ListView and override the relevant events as follows:
Imports System.Windows.Forms
Imports System.Drawing
Imports System.ComponentModel
<DesignerCategory("Code")>
Public Class ListViewEx
Inherits ListView
Private ht As ListViewHitTestInfo
Sub New()
MyBase.New
DoubleBuffered = True
OwnerDraw = True
FullRowSelect = True
End Sub
Public Property DrawFocusRectangle As Boolean = True
Protected Overrides Sub OnDrawColumnHeader(e As DrawListViewColumnHeaderEventArgs)
e.DrawDefault = True
End Sub
Protected Overrides Sub OnDrawItem(e As DrawListViewItemEventArgs)
If View = View.Details Then Return
If e.Item.Selected Then
e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds)
e.DrawFocusRectangle()
Else
e.DrawBackground()
End If
e.DrawText()
End Sub
Protected Overrides Sub OnDrawSubItem(e As DrawListViewSubItemEventArgs)
Using sf As New StringFormat With {
.Alignment = StringAlignment.Near,
.LineAlignment = StringAlignment.Center,
.Trimming = StringTrimming.EllipsisCharacter,
.FormatFlags = StringFormatFlags.NoWrap
},
br = New SolidBrush(e.SubItem.ForeColor)
Select Case e.Header.TextAlign
Case HorizontalAlignment.Center
sf.Alignment = StringAlignment.Center
Case HorizontalAlignment.Right
sf.Alignment = StringAlignment.Far
End Select
If e.Item.Selected Then
If e.ColumnIndex = 0 OrElse FullRowSelect Then
e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds)
End If
Else
e.DrawBackground()
End If
e.Graphics.DrawString(e.SubItem.Text, e.SubItem.Font, br, e.Bounds, sf)
End Using
'Here you go...
If DrawFocusRectangle AndAlso ht IsNot Nothing AndAlso
e.Item.Focused AndAlso e.SubItem Is ht.SubItem Then
Using pn As New Pen(Color.Orange, 2)
Dim r As New Rectangle(e.Bounds.X,
e.Bounds.Y,
e.Header.Width - 1,
e.Bounds.Height - 1)
e.Graphics.DrawRectangle(pn, r)
'or just draw focus rectangle ...
'ControlPaint.DrawFocusRectangle(e.Graphics, r)
End Using
End If
End Sub
Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
MyBase.OnMouseDown(e)
ht = HitTest(e.Location)
Invalidate()
End Sub
Protected Overrides Sub OnColumnWidthChanged(e As ColumnWidthChangedEventArgs)
MyBase.OnColumnWidthChanged(e)
Invalidate()
End Sub
End Class
Related
How to change default selection color of a ListView?
WinForms: Changing ForeColor of Selected item in ListView
ListView: MultiSelect items with mouse drag
The DataGridViewComboBoxColumn control can be difficult to work with. I've been fighting various permutations of this code for two long days, so I've decided to throw in the towel and seek some assistance.
The latest incarnation of weirdness is a ComboBox event handler that fires an increasing number of times for a single user action. Oddly, the rate of increase is an exact doubling of the count just preceding (i.e. 1, 2, 4, 8, 16, 32, 64 etc.)
To start things off, I'll explain what I'm trying to accomplish and also clarify some terminology.
I have a Dictionary(Of Integer, String). In my domain rules, I'm calling its Key property Channel and its Value property Label. I'm mapping each KeyValuePair to a third String value called Target. The Dictionary(Of Integer, String) items are fixed—they exist as a visual aid for the user, so he can easily select the Target from a List(Of String).
I've settled on a DataGridView control to provide this functionality. I'm using three columns, like so:
Note that already-mapped Target list items are displayed in a nearly-invisible color, so as to discourage the user from trying to use them again. (This is where the event handler problem comes in—when an already-mapped Target is selected for mapping to a different Label.)
I'm including my full code base below, but for a quick look here's the event handler that repeats:
Private Sub ComboBox_SelectionChangeCommitted(Sender As ComboBox, e As EventArgs)
' '
' Look for other labels that have already been mapped to this target '
' '
If Me.OtherTargetCells.Any(Function(Cell) Cell.FormattedValue = Sender.Text) Then
If Me.IsInteractiveChange Then
MsgBox("Target [] is already mapped to Label []. If you want to map Target [] to Label [], you must first set Label [] to [Not mapped].", MsgBoxStyle.Exclamation, Me.DataGridView.FindForm.Text)
Me.IsInteractiveChange = False
Sender.SelectedIndex = 0
Me.IsInteractiveChange = True
End If
End If
End Sub
And here's how I'm wiring it all up:
Public Sub New()
Task.Run(Sub()
Dim oHandler As DataGridViewEditingControlShowingEventHandler
While Me.DataGridView Is Nothing
End While
oHandler = New DataGridViewEditingControlShowingEventHandler(AddressOf DataGridView_EditingControlShowing)
RemoveHandler Me.DataGridView.EditingControlShowing, oHandler
AddHandler Me.DataGridView.EditingControlShowing, oHandler
End Sub)
End Sub
Private Sub DataGridView_EditingControlShowing(Sender As DataGridView, e As DataGridViewEditingControlShowingEventArgs)
Dim oComboBox As ComboBox
If TypeOf e.Control Is ComboBox Then
oComboBox = e.Control
oComboBox.DrawMode = DrawMode.OwnerDrawFixed
RemoveHandler oComboBox.DrawItem, New DrawItemEventHandler(AddressOf ComboBox_DrawItem)
AddHandler oComboBox.DrawItem, New DrawItemEventHandler(AddressOf ComboBox_DrawItem)
RemoveHandler oComboBox.SelectionChangeCommitted, New EventHandler(AddressOf ComboBox_SelectionChangeCommitted)
AddHandler oComboBox.SelectionChangeCommitted, New EventHandler(AddressOf ComboBox_SelectionChangeCommitted)
End If
End Sub
The repeat count multiplies when I select an already-mapped Target from a different list than previously (e.g. selecting twice from SCC doesn't increase the count, but selecting from SCC and then Scale does.)
I've tried many, many, many possible solutions for this—too many to list here and most of which I just don't remember—but none with any success.
What can I do to constrain the handler to fire only once for each selection change?
Mapping.TargetsColumn.vb
Namespace Mapping
Public Class TargetsColumn
Inherits DataGridViewComboBoxColumn
Public Sub New()
Task.Run(Sub()
Dim oHandler As DataGridViewEditingControlShowingEventHandler
While Me.DataGridView Is Nothing
End While
oHandler = New DataGridViewEditingControlShowingEventHandler(AddressOf DataGridView_EditingControlShowing)
RemoveHandler Me.DataGridView.EditingControlShowing, oHandler
AddHandler Me.DataGridView.EditingControlShowing, oHandler
End Sub)
End Sub
Private Sub DataGridView_EditingControlShowing(Sender As DataGridView, e As DataGridViewEditingControlShowingEventArgs)
Dim oComboBox As ComboBox
If TypeOf e.Control Is ComboBox Then
oComboBox = e.Control
oComboBox.DrawMode = DrawMode.OwnerDrawFixed
RemoveHandler oComboBox.DrawItem, New DrawItemEventHandler(AddressOf ComboBox_DrawItem)
AddHandler oComboBox.DrawItem, New DrawItemEventHandler(AddressOf ComboBox_DrawItem)
RemoveHandler oComboBox.SelectionChangeCommitted, New EventHandler(AddressOf ComboBox_SelectionChangeCommitted)
AddHandler oComboBox.SelectionChangeCommitted, New EventHandler(AddressOf ComboBox_SelectionChangeCommitted)
End If
End Sub
Private Sub ComboBox_DrawItem(Sender As ComboBox, e As DrawItemEventArgs)
Dim sThisTarget As String
Dim oForeColor As Color
Dim _
iSeparatorBottom,
iSeparatorRight,
iSeparatorLeft As Integer
Dim _
oSeparatorStart,
oSeparatorStop As Point
sThisTarget = DirectCast(Me.Items(e.Index), Target).Value
iSeparatorBottom = e.Bounds.Bottom - 2
iSeparatorRight = e.Bounds.Right
iSeparatorLeft = e.Bounds.Left
e.DrawBackground()
If e.Index = 0 Then
oSeparatorStart = New Point(iSeparatorLeft, iSeparatorBottom)
oSeparatorStop = New Point(iSeparatorRight, iSeparatorBottom)
oForeColor = SystemColors.HotTrack
e.Graphics.FillRectangle(SystemBrushes.Control, e.Bounds)
e.Graphics.DrawLine(SystemPens.ControlDark, oSeparatorStart, oSeparatorStop)
Else
If Me.OtherTargets.Contains(sThisTarget) Then
oForeColor = SystemColors.ControlLight
Else
oForeColor = e.ForeColor
End If
End If
Using oBrush As New SolidBrush(oForeColor)
e.Graphics.DrawString(sThisTarget, e.Font, oBrush, e.Bounds)
End Using
If e.State.HasFlag(DrawItemState.Focus) Then e.DrawFocusRectangle()
Me.DataGridView.FindForm.Text = sThisTarget
End Sub
Private Sub ComboBox_SelectionChangeCommitted(Sender As ComboBox, e As EventArgs)
' '
' Look for other labels that have already been mapped to this target '
' '
If Me.OtherTargetCells.Any(Function(Cell) Cell.FormattedValue = Sender.Text) Then
If Me.IsInteractiveChange Then
MsgBox("Target [] is already mapped to Label []. If you want to map Target [] to Label [], you must first set Label [] to [Not mapped].", MsgBoxStyle.Exclamation, Me.DataGridView.FindForm.Text)
Me.IsInteractiveChange = False
Sender.SelectedIndex = 0
Me.IsInteractiveChange = True
End If
End If
End Sub
Private ReadOnly Property OtherTargets As List(Of String)
Get
Return Me.OtherTargetCells.Select(Function(Cell) DirectCast(Cell.FormattedValue, String)).ToList
End Get
End Property
Private ReadOnly Property CurrentTargetCell As DataGridViewCell
Get
Return Me.AllTargetCells(Me.DataGridView.CurrentRow.Index)
End Get
End Property
Private ReadOnly Property AllTargetCells As List(Of DataGridViewCell)
Get
Dim oAllCells As IEnumerable(Of DataGridViewCell)
Dim oRows As IEnumerable(Of DataGridViewRow)
oRows = Me.DataGridView.Rows.Cast(Of DataGridViewRow)
oAllCells = oRows.SelectMany(Function(Row) Row.Cells.Cast(Of DataGridViewCell))
Return oAllCells.Where(Function(Cell) TypeOf Cell Is DataGridViewComboBoxCell).ToList
End Get
End Property
Private ReadOnly Property OtherTargetCells As List(Of DataGridViewCell)
Get
Return Me.AllTargetCells.Where(Function(Cell) Cell.RowIndex <> Me.RowIndex).ToList
End Get
End Property
Private ReadOnly Property RowIndex As Integer
Get
Return Me.DataGridView.CurrentRow.Index
End Get
End Property
Private IsInteractiveChange As Boolean = True
Private ReadOnly ComboBoxes As New Dictionary(Of Integer, ComboBox)
End Class
End Namespace
Form1.vb
Public Class Form1
Inherits Form
Public Sub New()
Dim oColTargets As Mapping.TargetsColumn
Dim oTargets As IEnumerable(Of String)
Dim oQuery As Func(Of Target, Boolean)
Dim sChannel As String
Dim oTarget As Target
Dim oMaps As Dictionary(Of Integer, String)
Dim oMap As Map
Dim _
oColChannels,
oColLabels As DataGridViewTextBoxColumn
Me.InitializeComponent()
Me.Targets.Add(New Target("Not mapped"))
sChannel = String.Empty
oQuery = Function(Target) Target.Value = sChannel
'oTargets = Reader.Client.Create.Call(Function(Service As Reader.IService) Service.GetChannelTargets)'
oTargets = New List(Of String) From {"Scale", "SCC", "CO", "O2"}
oTargets.ToList.ForEach(Sub(Target)
Me.Targets.Add(New Target(Target))
End Sub)
'oMaps = Reader.Client.Create.Call(Function(Service As Reader.IService) Service.GetChannelMaps)'
oMaps = New Dictionary(Of Integer, String) From {{3, "Test"}, {7, "SCC"}, {8, "Scale"}, {9, "CO"}, {10, "O2"}}
oMaps.ToList.ForEach(Sub(Map)
sChannel = Map.Value
If Me.Targets.Any(oQuery) Then
oTarget = Me.Targets.Single(oQuery)
Else
oTarget = Me.Targets.First
End If
oMap = New Map With {
.Channel = Map.Key,
.Label = Map.Value,
.Target = oTarget
}
Me.Maps.Add(oMap)
End Sub)
oColChannels = New DataGridViewTextBoxColumn With {
.DataPropertyName = NameOf(Map.Channel),
.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader,
.HeaderText = NameOf(Map.Channel),
.ReadOnly = True,
.Name = NameOf(oColChannels)
}
oColLabels = New DataGridViewTextBoxColumn With {
.DataPropertyName = NameOf(Map.Label),
.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader,
.HeaderText = NameOf(Map.Label),
.ReadOnly = True,
.Name = NameOf(oColLabels)
}
oColTargets = New Mapping.TargetsColumn With {
.DataPropertyName = NameOf(Map.Target),
.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
.DisplayMember = NameOf(Target.Value),
.ValueMember = NameOf(Target.Self),
.HeaderText = NameOf(Map.Target),
.DataSource = Me.Targets,
.Name = NameOf(oColTargets)
}
dgvMapping.AutoGenerateColumns = False
dgvMapping.Columns.AddRange({oColChannels, oColLabels, oColTargets})
For Each oColumn As DataGridViewColumn In dgvMapping.Columns
oColumn.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter
If oColumn.Index = 0 Then
oColumn.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
End If
Next
dgvMapping.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize
dgvMapping.DataSource = New BindingList(Of Map)(Me.Maps)
If dgvMapping.RowCount = 0 Then
dgvMapping.Height = 150
Else
dgvMapping.Height = ((dgvMapping.RowCount + 0) * dgvMapping.Rows(0).Height) + dgvMapping.ColumnHeadersHeight
End If
End Sub
Private Sub Form1_FormClosing(Sender As Form1, e As FormClosingEventArgs) Handles Me.FormClosing
Dim oPolicy As Target = Me.Maps.First.Target
Dim sName As String = Me.Maps.First.Channel
End Sub
Private Sub _dgvMapping_DataError(Sender As DataGridView, e As DataGridViewDataErrorEventArgs) Handles dgvMapping.DataError
MsgBox(e.Exception.Message, MsgBoxStyle.Critical, Me.Text)
End Sub
Private Targets As New BindingList(Of Target)
Private Maps As New List(Of Map)
End Class
Public Class Map
Public Property Channel As Integer
Public Property Label As String
Public Property Target As Target
End Class
Public Class Target
Public Sub New(Target As String)
Me.Value = Target
End Sub
Public ReadOnly Property Self As Target
Get
Return Me
End Get
End Property
Public ReadOnly Property Value As String
End Class
Form1.Designer.vb
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Partial Class Form1
Inherits System.Windows.Forms.Form
'Form overrides dispose to clean up the component list.'
<System.Diagnostics.DebuggerNonUserCode()>
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.'
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
Me.dgvMapping = New System.Windows.Forms.DataGridView()
CType(Me.dgvMapping, System.ComponentModel.ISupportInitialize).BeginInit()
Me.SuspendLayout()
' '
'dgvMapping'
' '
Me.dgvMapping.AllowUserToAddRows = False
Me.dgvMapping.AllowUserToDeleteRows = False
Me.dgvMapping.AllowUserToOrderColumns = True
Me.dgvMapping.AllowUserToResizeColumns = False
Me.dgvMapping.AllowUserToResizeRows = False
Me.dgvMapping.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize
Me.dgvMapping.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnEnter
Me.dgvMapping.Location = New System.Drawing.Point(12, 12)
Me.dgvMapping.Name = "dgvMapping"
Me.dgvMapping.RowHeadersVisible = False
Me.dgvMapping.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect
Me.dgvMapping.Size = New System.Drawing.Size(250, 150)
Me.dgvMapping.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.dgvMapping)
Me.Font = New System.Drawing.Font("Segoe UI", 8.0!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
Me.Name = "Form1"
Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
Me.Text = "Form1"
CType(Me.dgvMapping, System.ComponentModel.ISupportInitialize).EndInit()
Me.ResumeLayout(False)
End Sub
Friend WithEvents dgvMapping As DataGridView
End Class
Fixed.
I was instantiating a new event handler object for each AddHandler/RemoveHandler call.
When I removed the instantiations and used simple expressions instead, the ComboBoxes started behaving correctly.
Public Sub New()
Task.Run(Sub()
While Me.DataGridView Is Nothing
End While
RemoveHandler Me.DataGridView.EditingControlShowing, AddressOf DataGridView_EditingControlShowing
AddHandler Me.DataGridView.EditingControlShowing, AddressOf DataGridView_EditingControlShowing
End Sub)
End Sub
Private Sub DataGridView_EditingControlShowing(Sender As Object, e As DataGridViewEditingControlShowingEventArgs)
Dim oComboBox As ComboBox
If TypeOf e.Control Is ComboBox Then
oComboBox = e.Control
oComboBox.DrawMode = DrawMode.OwnerDrawFixed
RemoveHandler oComboBox.DrawItem, AddressOf ComboBox_DrawItem
AddHandler oComboBox.DrawItem, AddressOf ComboBox_DrawItem
RemoveHandler oComboBox.SelectionChangeCommitted, AddressOf ComboBox_SelectionChangeCommitted
AddHandler oComboBox.SelectionChangeCommitted, AddressOf ComboBox_SelectionChangeCommitted
End If
End Sub
I had to relax the Sender parameter types to Object in the event handler methods, but that didn't carry any serious consequence.
Private Sub DataGridView_EditingControlShowing(Sender As Object, e As DataGridViewEditingControlShowingEventArgs)
End Sub
Private Sub ComboBox_DrawItem(Sender As Object, e As DrawItemEventArgs)
End Sub
Private Sub ComboBox_SelectionChangeCommitted(Sender As Object, e As EventArgs)
End Sub
For what it's worth: I generally prefer to constrain the Sender parameter to the calling type, for more efficient coding, but that wasn't possible in this case. Nevertheless, the only impact was the need to cast the Sender in one place in one method body:
Dim oQuery = Function(Cell) Cell.FormattedValue = DirectCast(Sender, ComboBox).Text
It works as expected now.
I am really puzzled about my program right now because it acts really different according to its purpose what I am trying to do is that I if the text in textbox in the previous form is the same as the text in the textbox on the next form it will show picture1 which is a checkmark otherwise it will show the picture2 which is a crossmark but what happens is instead it will act correctly if one of the text is empty or null but if all textboxes has a value whether the texts on the texboxes satisfies the statement it will always show the picture2 which is a crossmark. I hope you can help me.Thanks in advance.
Imports System.Convert
Imports System.IO
Imports System.Windows.Forms.PictureBox
Imports System.Drawing.Image
Public Class Form4
Inherits System.Windows.Forms.Form
Private frm1 As Form1
Private frm2 As Form2
Public frm3 As Form3
Private frm4 As Form4
Private frm5 As Form5
Private Sub Form4_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim lbl3 As Integer
lbl3 = CInt(lbl3)
Me.Visible = False
End Sub
Public Sub New1(ByVal callerInstance As Form1)
' Call required if you add your constructor manually
InitializeComponent()
' save the instance of the Me variable passed to this constructor
frm1 = callerInstance
End Sub
Public Sub New5(ByVal callerInstance As Form2)
' Call required if you add your constructor manually
InitializeComponent()
' save the instance of the Me variable passed to this constructor
frm2 = callerInstance
End Sub
Public Sub New4(ByVal callerInstance As Form3)
' Call required if you add your constructor manually
InitializeComponent()
' save the instance of the Me variable passed to this constructor
frm3 = callerInstance
End Sub
Public Sub New3(ByVal callerInstance As Form4)
' Call required if you add your constructor manually
InitializeComponent()
' save the instance of the Me variable passed to this constructor
frm4 = callerInstance
End Sub
Public Sub New5(ByVal callerInstance As Form5)
' Call required if you add your constructor manually
InitializeComponent()
' save the instance of the Me variable passed to this constructor
frm5 = callerInstance
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim frm1 As Form1 = Form1
Dim frm2 As Form2 = Form2
Dim frm3 As Form3 = Form3
Dim frm5 As Form5 = Form5
frm5.Label21.Text = frm1.TextBox1.Text
frm5.Label21.ForeColor = Color.Black
frm5.Label22.Text = frm1.TextBox2.Text
frm5.Label22.ForeColor = Color.Black
frm5.Label23.Text = frm1.TextBox3.Text
frm5.Label23.ForeColor = Color.Black
frm5.Label24.Text = frm1.TextBox4.Text
frm5.Label24.ForeColor = Color.Black
frm5.Label25.Text = frm1.TextBox5.Text
frm5.Label25.ForeColor = Color.Black
frm5.Label26.Text = frm1.TextBox6.Text
frm5.Label26.ForeColor = Color.Black
frm5.Label27.Text = frm1.TextBox7.Text
frm5.Label27.ForeColor = Color.Black
frm2.Label28.Text = frm1.TextBox8.Text
frm2.Label28.ForeColor = Color.Black
frm5.Label29.Text = frm1.TextBox9.Text
frm5.Label29.ForeColor = Color.Black
frm5.Label30.Text = frm1.TextBox10.Text
frm5.Label30.ForeColor = Color.Black
frm5.Label31.Text = frm1.TextBox11.Text
frm5.Label31.ForeColor = Color.Black
frm5.Label32.Text = frm1.TextBox12.Text
frm5.Label32.ForeColor = Color.Black
frm5.Label33.Text = frm1.TextBox13.Text
frm5.Label33.ForeColor = Color.Black
frm5.Label34.Text = frm1.TextBox14.Text
frm5.Label34.ForeColor = Color.Black
frm5.Label35.Text = frm1.TextBox15.Text
frm5.Label35.ForeColor = Color.Black
frm5.Label36.Text = frm1.TextBox16.Text
frm5.Label36.ForeColor = Color.Black
frm5.Label37.Text = frm1.TextBox17.Text
frm5.Label37.ForeColor = Color.Black
frm5.Label38.Text = frm1.TextBox18.Text
frm5.Label38.ForeColor = Color.Black
frm5.Label39.Text = frm1.TextBox19.Text
frm5.Label39.ForeColor = Color.Black
frm5.Label40.Text = frm1.TextBox20.Text
frm5.Label40.ForeColor = Color.Black
Dim tb1 As TextBox = frm3.TextBox1
Dim tb2 As TextBox = frm3.TextBox2
Dim tb3 As TextBox = frm3.TextBox3
Dim tb4 As TextBox = frm3.TextBox4
Dim tb5 As TextBox = frm3.TextBox5
Dim tb6 As TextBox = frm3.TextBox6
Dim tb7 As TextBox = frm3.TextBox7
Dim tb8 As TextBox = frm3.TextBox8
Dim tb9 As TextBox = frm3.TextBox9
Dim tb10 As TextBox = frm3.TextBox10
If tb1.Text IsNot Nothing Then
If (frm1.TextBox2.Text.Equals(tb1.Text)) And frm1.TextBox2.Text = tb1.Text Then
frm5.PictureBox1.Image = Image.FromFile("D:\checkmark.jpg")
Else
frm5.PictureBox1.Image = Image.FromFile("D:\crossmark.jpg")
End If
Else
frm5.PictureBox1.Image = Image.FromFile("D:\crossmark.jpg")
End If
If tb2.Text IsNot Nothing Then
If (frm1.TextBox4.Text.Equals(tb2.Text)) And frm1.TextBox4.Text = tb2.Text Then
frm5.PictureBox2.Image = Image.FromFile("D:\checkmark.jpg")
Else
frm5.PictureBox2.Image = Image.FromFile("D:\crossmark.jpg")
End If
Else
frm5.PictureBox1.Image = Image.FromFile("D:\crossmark.jpg")
End If
If tb3.Text IsNot Nothing Then
If (frm1.TextBox6.Text.Equals(tb3.Text)) And frm1.TextBox6.Text = tb3.Text Then
frm5.PictureBox3.Image = Image.FromFile("D:\checkmark.jpg")
Else
frm5.PictureBox3.Image = Image.FromFile("D:\crossmark.jpg")
End If
Else
frm5.PictureBox3.Image = Image.FromFile("D:\crossmark.jpg")
End If
If tb4.Text IsNot Nothing Then
If (frm1.TextBox8.Text.Equals(tb4.Text)) And frm1.TextBox8.Text = tb4.Text Then
frm5.PictureBox4.Image = Image.FromFile("D:\checkmark.jpg")
Else
frm5.PictureBox4.Image = Image.FromFile("D:\crossmark.jpg")
End If
Else
frm5.PictureBox3.Image = Image.FromFile("D:\crossmark.jpg")
End If
If tb5.Text IsNot Nothing Then
If (frm1.TextBox10.Text.Equals(tb5.Text)) And frm1.TextBox10.Text = tb5.Text Then
frm5.PictureBox5.Image = Image.FromFile("D:\checkmark.jpg")
Else
frm5.PictureBox5.Image = Image.FromFile("D:\crossmark.jpg")
End If
Else
frm5.PictureBox3.Image = Image.FromFile("D:\crossmark.jpg")
End If
If tb6.Text IsNot Nothing Then
If (frm1.TextBox12.Text.Equals(tb6.Text)) And frm1.TextBox12.Text = tb6.Text Then
frm5.PictureBox6.Image = Image.FromFile("D:\checkmark.jpg")
Else
frm5.PictureBox6.Image = Image.FromFile("D:\crossmark.jpg")
End If
Else
frm5.PictureBox3.Image = Image.FromFile("D:\crossmark.jpg")
End If
If tb7.Text IsNot Nothing Then
If (frm1.TextBox14.Text.Equals(tb7.Text)) And frm1.TextBox14.Text = tb7.Text Then
frm5.PictureBox7.Image = Image.FromFile("D:\checkmark.jpg")
Else
frm5.PictureBox7.Image = Image.FromFile("D:\crossmark.jpg")
End If
Else
frm5.PictureBox3.Image = Image.FromFile("D:\crossmark.jpg")
End If
If tb8.Text IsNot Nothing Then
If (frm1.TextBox16.Text.Equals(tb8.Text)) And frm1.TextBox16.Text = tb8.Text Then
frm5.PictureBox8.Image = Image.FromFile("D:\checkmark.jpg")
Else
frm5.PictureBox8.Image = Image.FromFile("D:\crossmark.jpg")
End If
Else
frm5.PictureBox3.Image = Image.FromFile("D:\crossmark.jpg")
End If
If tb9.Text IsNot Nothing Then
If (frm1.TextBox18.Text.Equals(tb9.Text)) And frm1.TextBox18.Text = tb9.Text Then
frm5.PictureBox9.Image = Image.FromFile("D:\checkmark.jpg")
Else
frm5.PictureBox9.Image = Image.FromFile("D:\crossmark.jpg")
End If
Else
frm5.PictureBox3.Image = Image.FromFile("D:\crossmark.jpg")
End If
If tb10.Text IsNot Nothing Then
If (frm1.TextBox20.Text.Equals(tb10.Text)) And frm1.TextBox20.Text = tb10.Text Then
frm5.PictureBox10.Image = Image.FromFile("D:\checkmark.jpg")
Else
frm5.PictureBox10.Image = Image.FromFile("D:\crossmark.jpg")
End If
Else
frm5.PictureBox10.Image = Image.FromFile("D:\crossmark.jpg")
End If
If frm5 IsNot Nothing Then
frm5.Visible = False
frm5.Show() 'Show Second Form
Me.Hide()
End If
End Sub
Private Sub Form5HasBeenClosed(ByVal sender As Object, ByVal e As FormClosedEventArgs)
Throw New NotImplementedException
End Sub
End Class
I tried you're code and to make it work I needed to change a few things.
1e change If tb1.Text IsNot Nothing Then to:
If Not tb1.Text = "" Then" "Otherwise the else didn't work if I erased the textbox"
2e I needed to change frm1 to Form1 and frm5 to Form5"It gave me errors"
3e if you use If (frm1.TextBox2.Text.Equals(tb1.Text)) And frm1.TextBox2.Text = tb1.Text Then
"aren't you checking 2 times for the same ?"
so change it to:
If (Form1.TextBox2.Text.Equals(tb1.Text)) Then
Then the code works and does what it needs to do.
If Not tb1.Text = "" Then
If (Form1.TextBox2.Text.Equals(tb1.Text)) Then
Form5.PictureBox1.Image = Image.FromFile("D:\checkmark.jpg")
Else
Form5.PictureBox1.Image = Image.FromFile("D:\crossmark.jpg")
End If
Else
Form5.PictureBox1.Image = Image.FromFile("D:\crossmark.jpg")
End If
I'm trying to make navigation through controls with arrow keys (up/down).
To try my example just create a new form1 and paste this code into it.
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim tb As New TextBox
Dim cb As New CheckBox
Dim cbb As New ComboBox
Dim b1 As New Button
Dim b2 As New Button
With Me
.KeyPreview = True
.Size = New Size(350, 200)
With .Controls
.Add(tb)
With tb
.TabIndex = 0
.Location = New Point(95, 20)
.Text = "This is"
End With
.Add(cb)
With cb
.TabIndex = 1
.Location = New Point(95, 50)
.Checked = True
.Text = "Example checkbox"
.AutoSize = True
End With
.Add(cbb)
With cbb
.TabIndex = 2
.Location = New Point(95, 80)
.Text = "an Example"
.DropDownStyle = ComboBoxStyle.DropDownList
End With
.Add(b1)
With b1
.TabStop = False
.Location = New Point(90, 130)
.Text = "Nothing"
End With
.Add(b2)
With b2
.TabStop = False
.Location = New Point(170, 130)
.Text = "Exit"
AddHandler b2.Click, AddressOf b2_Click
End With
End With
End With
End Sub
Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
If e.KeyCode = Keys.Up Then
e.Handled = True
Me.SelectNextControl(Me.ActiveControl, False, True, True, True)
End If
If e.KeyCode = Keys.Down Then
e.Handled = True
Me.SelectNextControl(Me.ActiveControl, True, True, True, True)
End If
End Sub
Private Sub b2_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Me.Close()
End Sub
End Class
What happens?
When starting a program and navigating with arrows there havent 'focus rect' around controls and in some situation focus "run's out" to controls with tabstop = false??
But...
If I pass once with TAB key through controls after that navigating with arrows becomes good, focus rect appear's and everything is OK.
What may be problem here?
What to do that navigating with arrows behaves a same like with tab key immediately after program starts?
I find a solution to get things working as expected "through code" here:
C# code
And here is my translation to VB.
1) In some your public module add imports...
Imports System.Runtime.InteropServices
2) Put this declarations in same module:
<DllImport("user32.dll")> _
Private Sub SystemParametersInfo(ByVal uiAction As UInteger, ByVal uiParam As UInteger, ByRef pvParam As Integer, ByVal fWinIni As UInteger)
End Sub
' Constants used for User32 calls.
Const SPI_SETKEYBOARDCUES As UInteger = &H100B
3) Put this public function in same module:
''' <summary>
''' Change the setting programmatically
''' for keyboard shortcut Issue
''' </summary>
Public Sub GetAltKeyFixed()
Dim pv As Integer = 1
' Call to systemparametersinfo to set true of pv variable.
SystemParametersInfo(SPI_SETKEYBOARDCUES, 0, pv, 0)
'Set pvParam to TRUE to always underline menu access keys,
End Sub
4) From start place of your program (say Form1) just call:
GetAltKeyFixed()
Once is enough :)