Binding three state checkbox to nullable boolean

K

klachemin

Hi everyone. I've attached a piece of code that works and throws no
error... but the 'happy' checkbox is just a gray line when you run it.

It databinds a listbox to a collection of objects, and some text
fields, check boxes, and a slider bar to various properties of the
object. I was testing checkbox binding, and got the simple 'yes/no'
checkbox working, but the threestate checkbox isn't appearing
correctly.

To run this code, start a new project, double click the form, erase
what's there, and paste this in its place. Note that I'm using VB
2008.

Thanks for any assistance you can offer!

Option Explicit On
Option Infer Off
Option Strict On

Imports System.ComponentModel

Public Class Form1

Private WithEvents bs As BindingSource = New BindingSource()
Private listofdata As List(Of Data)

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim lst As ListBox = New ListBox()
Dim fieldnames() As String = {"txtName", "txtAge", "trkAge",
"ck3Happy", "chkMarried"}
Dim spacing As Integer = 3
Dim x, x2 As Integer
Dim y As Integer = spacing
Dim lbl As Label
Dim txt As TextBox
Dim trk As TrackBar
Dim chk As CheckBox
Dim prefix As String
Dim suffix As String
Dim propname As String
Dim b As Binding

' Load data
listofdata = LoadData()

' Set up binding source
bs.DataSource = listofdata

' Set up listbox to contain names of all objects
lst.Name = "lstData"
lst.IntegralHeight = False
lst.Height = Me.ClientRectangle.Height
lst.Anchor = AnchorStyles.Top Or AnchorStyles.Bottom Or
AnchorStyles.Left
Me.Controls.Add(lst)
lst.DisplayMember = "name"
lst.DataSource = bs

' Set up fields to contain properties of current object
x = lst.Width + spacing
x2 = x + 100
For Each fieldname As String In fieldnames

prefix = fieldname.Substring(0, 3)
suffix = fieldname.Substring(3)
propname = suffix.ToLower()

' Label
lbl = New Label()
lbl.Text = suffix & ":"
lbl.Width = 50
lbl.Left = x
lbl.Top = y
Me.Controls.Add(lbl)

' Bound control
If prefix = "txt" Then
txt = New TextBox()
txt.Name = fieldname
txt.Left = x2
txt.Top = y
Me.Controls.Add(txt)
txt.DataBindings.Add("Text", bs, propname)
ElseIf prefix = "trk" Then
trk = New TrackBar()
trk.Name = fieldname
trk.Left = x2
trk.Top = y
trk.Maximum = 200
trk.Width = 120
trk.Height = 50
Me.Controls.Add(trk)
trk.DataBindings.Add("Value", bs, propname)
ElseIf prefix = "ck3" Then
chk = New CheckBox
chk.Name = fieldname
chk.Left = x2
chk.Top = y
chk.Text = suffix
chk.ThreeState = True
Me.Controls.Add(chk)
b = New Binding("CheckState", bs, propname, True,
DataSourceUpdateMode.OnValidation, Nothing)
'AddHandler b.Format, AddressOf
NullableBooleanToCheckState
'AddHandler b.Parse, AddressOf
CheckStateToNullableBoolean
Try
chk.DataBindings.Add(b)
Catch ex As Exception
Debug.Print(ex.ToString)
End Try
ElseIf prefix = "chk" Then
chk = New CheckBox
chk.Name = fieldname
chk.Left = x2
chk.Top = y
chk.Text = suffix
Me.Controls.Add(chk)
b = New Binding("Checked", bs, propname)
Try
chk.DataBindings.Add(b)
Catch ex As Exception
Debug.Print(ex.ToString)
End Try
End If
y += lbl.Height + spacing
Next

End Sub

Private Function LoadData() As List(Of Data)
Dim lst As New List(Of Data)
lst.Add(New Data("John", 32, Nothing, True))
lst.Add(New Data("Carol", 22, True, False))
lst.Add(New Data("Frank", 58, False, True))
Return lst
End Function

Private Sub NullableBooleanToCheckState(ByVal sender As Object,
ByVal e As ConvertEventArgs)
If e.DesiredType IsNot GetType(CheckState) Then
Exit Sub
End If
Dim value As Boolean? = CType(e.Value, Boolean?)
If value Is Nothing Then
e.Value = CheckState.Indeterminate
ElseIf value = True Then
e.Value = CheckState.Checked
Else
e.Value = CheckState.Unchecked
End If
End Sub

Private Sub CheckStateToNullableBoolean(ByVal sender As Object,
ByVal e As ConvertEventArgs)
If e.DesiredType IsNot GetType(Boolean?) Then
Exit Sub
End If
Dim value As CheckState = CType(e.Value, CheckState)
Dim newvalue As Boolean?
If value = CheckState.Checked Then
newvalue = True
ElseIf value = CheckState.Indeterminate Then
newvalue = Nothing
Else
newvalue = False
End If
e.Value = newvalue
End Sub


Public Class ThreeStateCheckbox
Inherits CheckBox
Protected oBinding As Binding = Nothing
Public Sub New()
Me.ThreeState = True
End Sub
Public Sub DataBind(ByVal data As DataTable, ByVal Field As
String)
Me.oBinding = New Binding("CheckState", data, Field)
AddHandler Me.oBinding.Format, AddressOf Me.FormatHandler
End Sub
Private Sub FormatHandler(ByVal sender As Object, ByVal e As
ConvertEventArgs)
If e.Value Is Nothing Then
e.Value = CheckState.Indeterminate
ElseIf CType(e.Value, Boolean) = True Then
e.Value = CheckState.Checked
Else
e.Value = CheckState.Unchecked
End If
End Sub
End Class

Public Class Data
Implements INotifyPropertyChanged
Public Event PropertyChanged(ByVal sender As Object, ByVal e
As System.ComponentModel.PropertyChangedEventArgs) Implements
System.ComponentModel.INotifyPropertyChanged.PropertyChanged

Dim _name As String
Dim _age As Integer
Dim _happy As Boolean?
Dim _married As Boolean

Public Sub New(ByVal name As String, ByVal age As Integer,
ByVal happy As Boolean?, ByVal married As Boolean)
Me.name = name
Me.age = age
Me.happy = happy
Me.married = married
End Sub

Private Sub UpdateField(ByVal fieldname As String)
RaiseEvent PropertyChanged(Me, New
PropertyChangedEventArgs(fieldname))
End Sub

Public Property name() As String
Get
Return _name
End Get
Set(ByVal value As String)
If value.Equals(_name) Then
Exit Property
End If
_name = value
UpdateField("name")
End Set
End Property

Public Property age() As Integer
Get
Return _age
End Get
Set(ByVal value As Integer)
If value.Equals(_age) Then
Exit Property
End If
_age = value
UpdateField("age")
End Set
End Property

Public Property happy() As Boolean?
Get
Return _happy
End Get
Set(ByVal value As Boolean?)
If value.Equals(_happy) Then
Exit Property
End If
_happy = value
UpdateField("happy")
End Set
End Property

Public Property married() As Boolean
Get
Return _married
End Get
Set(ByVal value As Boolean)
If value.Equals(_married) Then
Exit Property
End If
_married = value
UpdateField("married")
End Set
End Property

End Class

End Class
 
P

Patrice

Your checkbox is hidden behind the slider as the slider is a bit
higher than a label. Also you'll have to uncomment the Format/Parse
event handlers. Finally I would suggest to never catch an exception
just to display it in the debug window where it could get unnoticed...

Hope this helps
 
P

Patrice

Correcting myself : the handlers are not needed as the checkbox seems
to handle the Nothing value just fine...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top