Two Way Data Binding of Combo Box VB.Net - vb.net

I am trying to get the two-way combo box binding work. I have a class which serves as source for combo box and i bind the selected item/value of the combo box to data table and the data table is bound to data grid view with binding source. It works but not as i expect it to be. I want to achieve two things.
Update the Data table Grid view as soon as selection changes in the combo box (force update of data)
Add binding to Age column
Here is my code. What is the right way to do. Any help would be highly appreciated. Thanks
Imports System.ComponentModel
Imports System.Runtime.CompilerServices
Public Class Form1
Implements INotifyPropertyChanged
Public BS As New BindingSource
Public ContactBL As BindingList(Of Contacts)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim contacts As New List(Of Contacts) From {
New Contacts() With {.FirstName = "Name1", .LastName = "LName1", .Age = 50},
New Contacts() With {.FirstName = "Name2", .LastName = "LName2", .Age = 39},
New Contacts() With {.FirstName = "Name3", .LastName = "LName3", .Age = 30},
New Contacts() With {.FirstName = "Name4", .LastName = "LName4", .Age = 66}}
ContactBL = New BindingList(Of Contacts)(contacts)
ComboBox1.DataSource = ContactBL
ComboBox1.DisplayMember = "FirstName"
ComboBox1.ValueMember = "LastName"
Dim table As New DataTable("Tab1")
table.Columns.Add("FirstName", GetType(String))
table.Columns.Add("LastName", GetType(String))
table.Columns.Add("Age", GetType(Integer))
table.Rows.Add("Name3", "LName3", 30)
table.Rows.Add("Name2", "LName2", 39)
BS.DataSource = table
DataGridView1.DataSource = BS
ComboBox1.DataBindings.Add("SelectedValue", BS, "LastName", True, DataSourceUpdateMode.OnPropertyChanged)
ComboBox1.DataBindings.Add("Text", BS, "FirstName", True, DataSourceUpdateMode.OnPropertyChanged)
DataGridView2.DataSource = ContactBL
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim nr = CType(ComboBox1.SelectedItem, Contacts)
Dim NewRow = DirectCast(BS.AddNew(), DataRowView)
NewRow("FirstName") = nr.FirstName
NewRow("LastName") = nr.LastName
NewRow("Age") = nr.Age
BS.EndEdit()
End Sub
Private _FirstName As String
Public Property FirstName() As String
Get
Return _FirstName
End Get
Set(ByVal value As String)
_FirstName = value
OnPropertyChanged()
End Set
End Property
Private _LastName As String
Public Property LastName() As String
Get
Return _LastName
End Get
Set(ByVal value As String)
_LastName = value
OnPropertyChanged()
End Set
End Property
Private _Age As Integer
Public Property Age() As Integer
Get
Return _Age
End Get
Set(ByVal value As Integer)
_Age = value
OnPropertyChanged()
End Set
End Property
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Overridable Sub OnPropertyChanged(<CallerMemberName>
Optional memberName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(memberName))
End Sub
Sub BindingComplete(ByVal sender As Object, ByVal e As BindingCompleteEventArgs)
If e.BindingCompleteContext = BindingCompleteContext.DataSourceUpdate AndAlso e.Exception Is Nothing Then e.Binding.BindingManagerBase.EndCurrentEdit()
End Sub
End Class
Public Class Contacts
Implements INotifyPropertyChanged
Private _firstName As String
Private _lastName As String
Private _Age As Integer
Public Property ContactId() As Integer
Public Property FirstName() As String
Get
Return _firstName
End Get
Set
_firstName = Value
OnPropertyChanged()
End Set
End Property
Public Property LastName() As String
Get
Return _lastName
End Get
Set
_lastName = Value
OnPropertyChanged()
End Set
End Property
Public Property Age() As Integer
Get
Return _Age
End Get
Set
_Age = Value
OnPropertyChanged()
End Set
End Property
Public ReadOnly Property FullName() As String
Get
Return $"{FirstName} {LastName}"
End Get
End Property
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Overridable Sub OnPropertyChanged(<CallerMemberName>
Optional memberName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(memberName))
End Sub
End Class
Thanks

Related

Custom class. Datagridview column text with image

Good afternoon!
There is a custom class that adds a text column with an image to the DataGridView.
Public Class DataGridViewTextAndImageColumn
Inherits DataGridViewTextBoxColumn
Private imageValue As Image
Private imageSize_Renamed As Size
Public Sub New()
CellTemplate = New TextAndImageCell()
End Sub
Public Overrides Function Clone() As Object
Dim c As DataGridViewTextAndImageColumn = TryCast(MyBase.Clone(), DataGridViewTextAndImageColumn)
c.imageValue = imageValue
c.imageSize_Renamed = imageSize_Renamed
Return c
End Function
Public Property Image() As Image
Get
Return imageValue
End Get
Set(ByVal value As Image)
If Image IsNot value Then
imageValue = value
imageSize_Renamed = value.Size
If InheritedStyle IsNot Nothing Then
Dim inheritedPadding As Padding = InheritedStyle.Padding
DefaultCellStyle.Padding = New Padding(imageSize_Renamed.Width, inheritedPadding.Top, inheritedPadding.Right, inheritedPadding.Bottom)
End If
End If
End Set
End Property
Friend ReadOnly Property ImageSize() As Size
Get
Return imageSize_Renamed
End Get
End Property
End Class
Public Class TextAndImageCell
Inherits DataGridViewTextBoxCell
Private imageValue As Image
Private imageSize As Size
Public Overrides Function Clone() As Object
Dim c As TextAndImageCell = TryCast(MyBase.Clone(), TextAndImageCell)
c.imageValue = imageValue
c.imageSize = imageSize
Return c
End Function
Public Property Image() As Image
Get
If OwningColumn Is Nothing OrElse Me.OwningTextAndImageColumn Is Nothing Then
Return imageValue
ElseIf imageValue IsNot Nothing Then
Return imageValue
Else
Return OwningTextAndImageColumn.Image
End If
End Get
Set(ByVal value As Image)
If imageValue IsNot value Then
imageValue = value
imageSize = value.Size
Dim inheritedPadding As Padding = InheritedStyle.Padding
Style.Padding = New Padding(imageSize.Width, inheritedPadding.Top, inheritedPadding.Right, inheritedPadding.Bottom)
End If
End Set
End Property
Protected Overrides Sub Paint(ByVal graphics As Graphics, ByVal clipBounds As Rectangle, ByVal cellBounds As Rectangle, ByVal rowIndex As Integer, ByVal cellState As DataGridViewElementStates, ByVal value As Object, ByVal formattedValue As Object, ByVal errorText As String, ByVal cellStyle As DataGridViewCellStyle, ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle, ByVal paintParts As DataGridViewPaintParts)
' Paint the base content
MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)
If Image IsNot Nothing Then
' Draw the image clipped to the cell.
Dim container As Drawing2D.GraphicsContainer = graphics.BeginContainer()
graphics.SetClip(cellBounds)
graphics.DrawImageUnscaled(Image, cellBounds.Location)
graphics.EndContainer(container)
End If
End Sub
Private ReadOnly Property OwningTextAndImageColumn() As DataGridViewTextAndImageColumn
Get
Return TryCast(OwningColumn, DataGridViewTextAndImageColumn)
End Get
End Property
End Class
Form:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
With DataGridView1
.DefaultCellStyle.WrapMode = DataGridViewTriState.True
.Columns(1).DefaultCellStyle.WrapMode = DataGridViewTriState.True
.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells
.SelectionMode = DataGridViewSelectionMode.FullRowSelect
End With
End Sub
End Class
Result of work:
The question is:
The question is:
When a column is line-wrapped, the text is centered vertically in the cell. How to make a picture in a cell also centered regardless of the line height?

I get error rdr is not declared

With this line of code
using (rdr as mysqldatareader = cmd.executereader())
I get an error saying rdr is not declared. When I remove the brackets so that it becomes
Using rdr As MySqlDataReader = cmd.ExecuteReader()
I get error on this line tmpObj.No = rdr("No").ToString()saying No is not a member of the project.Form.Appdata and this line
tmpObj.Template = templa8 and Template is not a member of the project.Form.AppData. Note that I have already put this: Private FPList As New List(Of AppData) at the class level, as a member. Definitely I'm doing something wrong. Any suggestions?
'THIS NEEDS TO BE AT THE CLASS-LEVEL, AS A MEMBER
'Private FPList As New List(Of AppData)
Public Class AppData
Public Sub Update()
RaiseEvent OnChange()
End Sub
Public Event OnChange()
Public FPList As New List(Of AppData)
Public IsEventHandlerSucceeds As Boolean = True
Public IsFeatureSetMatched As Boolean = False
Public FalseAcceptRate As Integer = 0
Public Sub Update()
RaiseEvent OnChange()
End Sub
Public Event OnChange()
Public FPList As New List(Of AppData)
End Class
Private Sub Me_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.Load
Init()
StartCapture()
Dim sql As String = "SELECT * FROM new_case_file"
Using conn As New MySqlConnection("**** "), _
cmd As New MySqlCommand(sql, conn)
conn.Open()
Using (rdr As MySqlDataReader = cmd.ExecuteReader())
FPList.Clear()
While (rdr.Read())
Dim tmpObj As New AppData
tmpObj.No = rdr("No").ToString()
Dim fpBytes As Byte() = rdr("FingerPrint")
Using MemStream As New IO.MemoryStream(fpBytes)
Dim templa8 As New DPFP.Template()
templa8.DeSerialize(MemStream)
tmpObj.Template = templa8
End Using
FPList.Add(tmpObj)
End While
rdr.Close()
End Using
End Using
End Sub
You correct that error by adding the following to your AppData class
Private _No As String
Public Property No As String
Get
Return _No
End Get
Set(value as String)
_No = value
End Set
End Property
Private _Template As DPFP.Template
Public Property Template As DPFP.Template
Get
Return _Template
End Get
Set(value as DPFP.Template)
_Template = value
End Set
End Property
but that will not necessarily make your code work.

Having trouble populating listview box with vendor info

When the form loads there is a combo box where you select a GL account. Once one is selected, then I click the Get Vendor button to load the vendor information. I'm having problems with the code mainly on the form.vb. I need to populate the listview box with the vendor information and I'm not sure what I did wrong. I have referenced the payables class library etc. Getting error at vendor.count on form.vb. I haven't input the database info on Payables.DB b/c I'm not sure what it yes. Thanks.
Public Class Vendor
Dim m_VendorName As Integer
Dim m_FirstName As String
Dim m_LastName As String
Dim m_City As String
Dim m_State As String
Public Sub New()
End Sub
Public Property VendorName() As String
Get
Return m_VendorName
End Get
Set(ByVal value As String)
m_VendorName = value
End Set
End Property
Public Property FirstName() As String
Get
Return m_FirstName
End Get
Set(ByVal value As String)
m_FirstName = value
End Set
End Property
Public Property LastName() As String
Get
Return m_LastName
End Get
Set(ByVal value As String)
m_FirstName = value
End Set
End Property
Public Property State() As String
Get
Return m_State
End Get
Set(value As String)
m_State = value
End Set
End Property
Public Property City() As String
Get
Return m_City
End Get
Set(value As String)
m_City = value
End Set
End Property
End Class
Imports System.Data.SqlClient
Public Class VendorDB
Public Shared Function GetVendors() As List(Of Vendor)
Dim vendorList As New List(Of Vendor)
Dim connection As SqlConnection = PayablesDB.GetConnection
Dim selectStatement As String =
"SELECT VendorName, FirstName, Last Name, State, City " &
"FROM Vendor " &
"ORDER BY Description"
Dim selectCommand As New SqlCommand(selectStatement, connection)
Try
connection.Open()
Dim reader As SqlDataReader = selectCommand.ExecuteReader()
Dim vendor As Vendor
Do While reader.Read
vendor = New Vendor
vendor.VendorName = (reader("VendorName")).ToString
vendor.FirstName = reader("Firstname").ToString
vendor.LastName = (reader("LastName")).ToString
vendor.State = (reader("State")).ToString
vendor.City = (reader("City")).ToString
vendorList.Add(vendor)
Loop
reader.Close()
Catch ex As SqlException
Throw ex
Finally
connection.Close()
End Try
Return vendorList
End Function
End Class
Public Class GLAccount
Private m_Description As String
Public Sub New()
End Sub
Public Property Description() As String
Get
Return m_Description
End Get
Set(ByVal value As String)
m_Description = value
End Set
End Property
Imports System.Data.SqlClient
Public Class GLAccountDB
Public Shared Function GetGLAccountList() As List(Of GLAccount)
Dim accountList As New List(Of GLAccount)
Dim connection As SqlConnection = PayablesDB.GetConnection
Dim selectStatement As String =
"SELECT Description " &
"FROM GLAccounts " &
"ORDER BY Description"
Dim selectCommand As New SqlCommand(selectStatement, connection)
Try
connection.Open()
Dim reader As SqlDataReader = selectCommand.ExecuteReader()
Dim account As GLAccount
Do While reader.Read
account = New GLAccount
account.Description = reader("Description").ToString
accountList.Add(account)
Loop
reader.Close()
Catch ex As SqlException
Throw ex
Finally
connection.Close()
End Try
Return accountList
End Function
End Class
Now this is what I have referred to the payables(form and validator class)
Public Class Validator
Public Shared Function IsPresent(control As Control) As Boolean
Dim comboBox As ComboBox = CType(control, ComboBox)
If comboBox.SelectedIndex = -1 Then
MessageBox.Show(comboBox.Tag.ToString & " is a required field.")
comboBox.Select()
Return False
Else
Return True
End If
End Function
End Class
Payables
Public Class Form1
Dim vendorList As List(Of Vendor)
Dim accountList As List(Of GLAccount)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LoadComboBoxes()
End Sub
Private Sub LoadComboBoxes()
accountList = GLAccountDB.GetGLAccountList
cboAccounts.DataSource = accountList
cboAccounts.DisplayMember = "Description"
End Sub
Private Sub btnGetVendors_Click(sender As Object, e As EventArgs) Handles btnGetVendors.Click
Dim vendorList As List(Of Vendor)
Try
If Vendor.Count > 0 Then
vendorList = VendorDB.GetVendors()
Else
MessageBox.Show("All invoices were paid in full")
End If
Catch ex As Exception
End Try
End Sub
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
Me.Close()
End Sub
End Class

Inheriting DataGridView and changing rows type

I've a control named UIGrid which is inherited from DataGridView
Now, I want to change the Rows property type from DataGridViewRowCollection to UIGridRowCollection
I've overloaded the Rows property to return my type but it's not working as i want
I need that when i set a DataSource for the grid, It adds UIGridRow objects instead of DataGridViewRow
How can i make that possible ???
NOTE: The control is used in a solution with 45 project, So i can't change to a third-party solution
Here is a sample code:
Public Class UIGrid : Inherits DataGridView
Private _Rows As UIGridRowCollection
Public Overloads ReadOnly Property Rows As UIGridRowCollection
Get
If _Rows Is Nothing Then
_Rows = New UIGridRowCollection(Me)
End If
Return _Rows
End Get
End Property
End Class
Public Class UIGridRow : Inherits DataGridViewRow
Public Property ChildControl As Control
End Class
Public Class UIGridRowCollection : Inherits DataGridViewRowCollection
Public Sub New(grid As UIGrid)
MyBase.New(CType(grid, DataGridView))
End Sub
Public Overloads Function Add(row As UIGridRow) As Integer
Return MyBase.Add(row)
End Function
End Class
Now, When i try to use the UIGrid control and add rows to it, I face the error:
Row index provided is out of range.
sample code:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.UiGrid1.Columns.Add("Id", "Id")
Me.UiGrid1.Columns.Add("Name", "Name")
For i As Integer = 1 To 10
Dim row As New UIGridRow
row.CreateCells(Me.UiGrid1)
row.Cells(0).Value = i
row.Cells(1).Value = "Employee " & i.ToString
Me.UiGrid1.Rows.Add(row)
Next
End Sub
And when i set the DataSource property for the grid, The Rows property still counts 0, It seems that the grid doesn't use the overloaded Rows property
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dt As New DataTable
dt.Columns.Add("Id", GetType(Integer))
dt.Columns.Add("Name", GetType(String))
For i As Integer = 1 To 10
dt.Rows.Add(i, "Name " & i)
Next
Me.UiGrid1.DataSource = dt
End Sub
I need that when i use DataSource property, The grid uses the overloaded Rows property and adds rows of type UIGridRow instead of DataGridViewRow
I am actually facing same problem ... i solved like this (not elegant maybe) ...
Not sure will work with datasource property - not tested
Imports System.Windows.Forms
Public Class myGrid : Inherits DataGridView
Public Overloads ReadOnly Property MyRows As List(Of UIGridRow)
Get
Dim oLst As New List(Of UIGridRow)
For Each ORow As DataGridViewRow In MyBase.Rows
oLst.Add(CType(ORow, UIGridRow))
Next
MyRows = oLst
End Get
End Property
Public Overloads ReadOnly Property MySelectedRows As List(Of UIGridRow)
Get
Dim oLst As New List(Of UIGridRow)
For Each oRow As DataGridViewRow In MyBase.SelectedRows
oLst.Add(CType(oRow, UIGridRow))
Next
MySelectedRows = oLst
End Get
End Property
Public Class UIGridRow : Inherits DataGridViewRow
Public Property Checked As Boolean
End Class
Public Overloads ReadOnly Property CurrentRow As UIGridRow
Get
Return CType(MyBase.CurrentRow, UIGridRow)
End Get
End Property
End Class
and on test form:
Imports myGrid.myGrid
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
MyGrid1.Columns.Add("Id", "Id")
MyGrid1.Columns.Add("Name", "Name")
For i As Integer = 1 To 10
Dim row As New myGrid.myGrid.UIGridRow
row.CreateCells(MyGrid1)
row.Cells(0).Value = i
row.Cells(1).Value = "Employee " & i.ToString
row.Checked = (i < 5)
MyGrid1.Rows.Add(row)
Next
End Sub
Private Sub MyGrid1_SelectionChanged(sender As Object, e As System.EventArgs) Handles MyGrid1.SelectionChanged
Debug.Print(CStr(MyGrid1.MyRows(MyGrid1.CurrentRow.Index).Checked))
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
For Each oRow As UIGridRow In MyGrid1.MySelectedRows
oRow.Cells(1).Style.BackColor = Color.Red
Next
End Sub
End Class

vb.net: How to prevent the dropdown of a checked combobox from closing after checking or unchecking an item

I would like to prevent the dropdown list from closing when the user checks or unchecks a checkbox in a checked combobox.
I have copied some Microsoft code to created a checked combobox. As it didn't work out-of-the-box, I did some customizing.
Here's my code:
Imports System.ComponentModel
Imports System.Collections.ObjectModel
Public Class CheckedCombobox
Inherits ComboBox
Public Event ItemCheck(ByVal sender As Object, ByVal e As System.Windows.Forms.ItemCheckEventArgs)
<Browsable(False)> _
Public Overloads ReadOnly Property Items() As ComboBox.ObjectCollection
Get
Return MyBase.Items
End Get
End Property
Private WithEvents _ItemCollection As New ObservableCollection(Of String)
Public Property ItemCollection As ObservableCollection(Of String)
Get
Return _ItemCollection
End Get
Set(value As ObservableCollection(Of String))
_ItemCollection = value
End Set
End Property
Private _ItemDictionary As New Dictionary(Of String, Boolean)
Public ReadOnly Property ItemDictionary As Dictionary(Of String, Boolean)
Get
Return _ItemDictionary
End Get
End Property
Public ReadOnly Property CheckedItemCollection As List(Of String)
Get
Return New List(Of String)(From item In ItemDictionary Where item.Value = True Select item.Key)
End Get
End Property
Public ReadOnly Property UnCheckedItemCollection As List(Of String)
Get
Return New List(Of String)(From item In ItemDictionary Where item.Value = False Select item.Key)
End Get
End Property
Public Sub setCheckState(ByVal key As String, ByVal checkstate As Boolean)
_ItemDictionary(key) = checkstate
End Sub
Public Function getCheckState(ByVal key As String)
Return (_ItemDictionary(key))
End Function
Public Sub New()
Me.DrawMode = Windows.Forms.DrawMode.OwnerDrawVariable
End Sub
Protected Overrides Sub OnCreateControl()
MyBase.OnCreateControl()
For Each item In ItemCollection
_ItemDictionary.Add(item, False)
Next
End Sub
Private Sub ItemsChanged(ByVal sender As Object, ByVal e As System.Collections.Specialized.NotifyCollectionChangedEventArgs) Handles _ItemCollection.CollectionChanged
Select Case e.Action
Case Specialized.NotifyCollectionChangedAction.Add
If e.NewStartingIndex = ItemDictionary.Count Then
_ItemDictionary.Add(e.NewItems(0), False)
MyBase.Items.Add(e.NewItems(0))
End If
Case Specialized.NotifyCollectionChangedAction.Remove
_ItemDictionary.Remove(MyBase.Items(e.OldStartingIndex))
MyBase.Items.RemoveAt(e.OldStartingIndex)
Case Specialized.NotifyCollectionChangedAction.Move
Dim _item As Object = MyBase.Items(e.OldStartingIndex)
MyBase.Items.RemoveAt(e.OldStartingIndex)
MyBase.Items.Insert(e.NewStartingIndex, _item)
Case Specialized.NotifyCollectionChangedAction.Replace
Throw New Exception("Not implemented yet!")
Case Specialized.NotifyCollectionChangedAction.Reset
Dim _checkeditems As New List(Of String)(CheckedItemCollection)
MyBase.Items.Clear()
MyBase.Items.AddRange(_ItemCollection.ToArray)
_ItemDictionary.Clear()
For Each item In _ItemCollection
_ItemDictionary.Add(item, _checkeditems.Contains(item))
Next
End Select
Me.Invalidate()
End Sub
Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)
e.DrawBackground()
Dim p As Point = e.Bounds.Location
If e.Index >= 0 Then
p.Offset(1, 1)
If getCheckState(MyBase.Items(e.Index)) Then
CheckBoxRenderer.DrawCheckBox(e.Graphics, p, VisualStyles.CheckBoxState.CheckedNormal)
Else
CheckBoxRenderer.DrawCheckBox(e.Graphics, p, VisualStyles.CheckBoxState.UncheckedNormal)
End If
p.Offset(12, 0)
e.Graphics.DrawString(MyBase.GetItemText(Me.Items(e.Index)), e.Font, New SolidBrush(e.ForeColor), p.X, p.Y)
End If
If e.State = DrawItemState.Selected Then
e.DrawFocusRectangle()
End If
MyBase.OnDrawItem(e)
End Sub
Private Sub checkedChanged(ByVal index As Integer)
Dim checked As Boolean = _ItemDictionary(MyBase.Items.Item(index))
If checked Then
_ItemDictionary(MyBase.Items.Item(index)) = False
RaiseEvent ItemCheck(Me, New ItemCheckEventArgs(index, CheckState.Unchecked, CheckState.Checked))
Else
_ItemDictionary(MyBase.Items.Item(index)) = True
RaiseEvent ItemCheck(Me, New ItemCheckEventArgs(index, CheckState.Checked, CheckState.Unchecked))
End If
Me.Invalidate()
End Sub
Private n As nWindow = Nothing
Private Const WM_CTLCOLORLISTBOX As Integer = &H134
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
MyBase.WndProc(m)
If m.Msg = WM_CTLCOLORLISTBOX Then
If n Is Nothing Then
n = New nWindow(Me)
n.AssignHandle(m.LParam)
AddHandler n.checkedChanged, AddressOf checkedChanged
End If
End If
End Sub
Private Sub CheckedCombobox_Click(sender As Object, e As System.EventArgs) Handles Me.SelectedIndexChanged
Debugger.Break()
End Sub
End Class
Public Class nWindow
Inherits NativeWindow
Private Const WM_LBUTTONDOWN As Integer = &H201
Private _combobox As CheckedCombobox
Public Event checkedChanged(ByVal index As Integer)
Public Sub New(ByVal cb As CheckedCombobox)
_combobox = cb
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_LBUTTONDOWN Then
Dim itemHeight As Integer = _combobox.ItemHeight
If New Point(m.LParam.ToInt32).Y \ itemHeight <= _combobox.Items.Count - 1 And New Point(m.LParam.ToInt32).Y \ itemHeight >= 0 Then
If New Point(m.LParam.ToInt32).X >= 1 And New Point(m.LParam.ToInt32).X <= 11 Then
RaiseEvent checkedChanged(_combobox.SelectedIndex)
End If
End If
End If
MyBase.WndProc(m)
End Sub
End Class
The code below seems to work correctly. It does what I set out to do.
(Note: I have only shown the changed routines)
Private Sub checkedChanged(ByVal index As Integer)
Dim checked As Boolean = _ItemDictionary(MyBase.Items.Item(index))
If checked Then
_ItemDictionary(MyBase.Items.Item(index)) = False
RaiseEvent ItemCheck(Me, New ItemCheckEventArgs(index, CheckState.Unchecked, CheckState.Checked))
Else
_ItemDictionary(MyBase.Items.Item(index)) = True
RaiseEvent ItemCheck(Me, New ItemCheckEventArgs(index, CheckState.Checked, CheckState.Unchecked))
End If
Me.SelectedIndex = -1
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_LBUTTONDOWN Then
Dim itemHeight As Integer = _combobox.ItemHeight
If New Point(m.LParam.ToInt32).Y \ itemHeight <= _combobox.Items.Count - 1 And New Point(m.LParam.ToInt32).Y \ itemHeight >= 0 Then
If New Point(m.LParam.ToInt32).X >= 1 And New Point(m.LParam.ToInt32).X <= 11 Then
RaiseEvent checkedChanged(_combobox.SelectedIndex)
Return
End If
End If
End If
MyBase.WndProc(m)
End Sub
I am not hundred percent sure about not calling MyBase.WndProc(), but I did not notice any side-effects yet.