绑定列表框会在数据刷新时将项目置为不可见。为什么?

时间:2014-07-08 12:48:47

标签: vb.net

我有一个绑定到列表的列表框是一个类。一切正常,直到我尝试将新项目添加到列表中。在此过程中,数据源设置为无需刷新列表,并且显然是“刷新”。没有做到。列表得到刷新,绑定到列表框数据的其他控件显示列表在那里并且是正确的但是列表显示为空,尽管它显示滚动条。我试图改变字体颜色,以防万一..没什么!

有人知道为什么会这样吗?怎么解决?还是更好的刷新方法?

代码:

Private Sub btnNew_Click(sender As Object, e As EventArgs) Handles btnNew.Click

    'lbNames is the listbox carrying all the data
    Dim oContacts As List(Of clsContact) = lbNames.DataSource
    lbNames.DataSource = Nothing

    'Build the new Item, add it to the collection
    Dim oNewCont As New clsContact
    oNewCont.Editable = True
    oNewCont.IsActive = True
    oNewCont.Firstname = "Jimmy"
    oNewCont.Lastname = "Smith"
    oContacts.Add(oNewCont)

    lbNames.Refresh()

    ' Re-Set up Autocomplete text box
    Dim MySource As New AutoCompleteStringCollection()
    For Each oc As clsContact In oContacts
        MySource.Add(oc.FullName)
    Next
    txtName.AutoCompleteMode = AutoCompleteMode.Suggest
    txtName.AutoCompleteCustomSource = MySource
    txtName.AutoCompleteSource = AutoCompleteSource.CustomSource

    'Set List Box data back to the collection
    lbNames.DataSource = oContacts
    lbNames.DisplayMember = "FullName"

End Sub

首发加载:

Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    Dim oCont As List(Of clsContact)
    lbNames.DrawMode = DrawMode.OwnerDrawVariable

    Dim oTypes As List(Of clsPhoneType) = loadTypes()
    cboPhoneType.DataSource = oTypes
    cboPhoneType.DisplayMember = "Type"
    cboPhoneType.ValueMember = "ID"

    oCont = LoadNames()
    lbNames.DataSource = oCont
    lbNames.DisplayMember = "FullName"

    Dim MySource As New AutoCompleteStringCollection()
    For Each oc As clsContact In oCont
        MySource.Add(oc.FullName)
    Next
    txtName.AutoCompleteMode = AutoCompleteMode.Suggest
    txtName.AutoCompleteCustomSource = MySource
    txtName.AutoCompleteSource = AutoCompleteSource.CustomSource
End Sub

Private Sub lbNames_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles lbNames.DrawItem

    e.DrawBackground()

    Dim textBrush As Brush = Brushes.Black
    Dim drawFont As System.Drawing.Font = e.Font

    If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
        e.Graphics.FillRectangle(Brushes.WhiteSmoke, e.Bounds)
    End If

    Dim oCont As clsContact = DirectCast(sender, System.Windows.Forms.ListBox).Items(e.Index)
    If oCont.IsActive Then
        textBrush = Brushes.Black
        If oCont.IsDirty Then textBrush = Brushes.LightCoral
    Else
        textBrush = Brushes.LightGray
    End If

    Dim str = oCont.FullName
    e.Graphics.DrawString(str, e.Font, textBrush, e.Bounds, StringFormat.GenericDefault)
    e.DrawFocusRectangle()

End Sub

enter image description here

2 个答案:

答案 0 :(得分:0)

您使用了错误的工具。 List(Of T)并未提出任何事件。当绑定到控件时,控件不知道是否添加/移除/移动了任何项目。幸运的是,BindingList(Of T)来救援。每当修改列表时,它都会引发ListChanged事件。作为奖励,如果您的类/模型实现INotifyPropertyChanged接口,则控件也将反映属性更改。

lbNames.DataSource = New BindingList(Of clsContact)(oCont)

这是一个示例表单,向您展示基础知识:

Imports System.ComponentModel

Public Class Form1

    Public Sub New()
        Me.InitializeComponent()
        Me.btnAdd = New Button With {.TabIndex = 0, .Dock = DockStyle.Top, .Height = 30, .Text = "Add new contact"}
        Me.btnChange = New Button With {.TabIndex = 1, .Dock = DockStyle.Top, .Height = 30, .Text = "Change random contact name"}
        Me.lbContacts = New ListBox With {.TabIndex = 2, .Dock = DockStyle.Fill}
        Me.Controls.AddRange({Me.lbContacts, Me.btnChange, Me.btnAdd})
    End Sub

    Private Sub HandleMeLoad(sender As Object, e As EventArgs) Handles Me.Load
        Dim list As New List(Of Contact)
        For i As Integer = 1 To 10
            list.Add(New Contact With {.Name = String.Format("Contact # {0}", i)})
        Next
        Me.lbContacts.DataSource = New BindingList(Of Contact)(list)
        Me.lbContacts.DisplayMember = "Name"
    End Sub

    Private Sub HandleButtonAddClick(sender As Object, e As EventArgs) Handles btnAdd.Click
        Dim list As BindingList(Of Contact) = DirectCast(Me.lbContacts.DataSource, BindingList(Of Contact))
        list.Add(New Contact With {.Name = String.Format("Contact # {0}", (list.Count + 1))})
    End Sub

    Private Sub HandleButtonChangeClick(sender As Object, e As EventArgs) Handles btnChange.Click
        Static rnd As New Random()
        Dim list As BindingList(Of Contact) = DirectCast(Me.lbContacts.DataSource, BindingList(Of Contact))
        If (list.Count > 0) Then
            With list.Item(rnd.Next(0, list.Count))
                .Name = Guid.NewGuid().ToString()
            End With
        End If
    End Sub

    Public Class Contact
        Implements INotifyPropertyChanged
        Public Event PropertyChanged As PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
        Public Property Name As String
            Get
                Return Me.m_name
            End Get
            Set(value As String)
                If (value <> Me.m_name) Then
                    Me.m_name = value
                    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Name"))
                End If
            End Set
        End Property
        Private m_name As String
    End Class

    Private WithEvents btnAdd As Button
    Private WithEvents btnChange As Button
    Private WithEvents lbContacts As ListBox

End Class

答案 1 :(得分:0)

似乎解决这个问题的方法是将drawmode翻转回正常状态。 添加:         lbNames.DrawMode = DrawMode.Normal         lbNames.DrawMode = DrawMode.OwnerDrawVariable 解决了这个问题。

我想正在发生的事情是绘图处理程序由于某种原因而变得断开连接,因此在附加数据源时不会重绘列表的竞争。

我的新工作代码:     Private Sub btnNew_Click(sender as Object,e As EventArgs)处理btnNew.Click

    'lbNames is the listbox carrying all the data
    Dim oContacts As List(Of clsContact) = lbNames.DataSource
    lbNames.DataSource = Nothing

    'Build the new Item, add it to the collection
    Dim oNewCont As New clsContact
    oNewCont.Editable = True
    oNewCont.IsActive = True
    oNewCont.Firstname = "Jimmy"
    oNewCont.Lastname = "Smith"
    oContacts.Add(oNewCont)

    ' Re-Set up Autocomplete text box
    Dim MySource As New AutoCompleteStringCollection()
    For Each oc As clsContact In oContacts
        MySource.Add(oc.FullName)
    Next
    txtName.AutoCompleteMode = AutoCompleteMode.Suggest
    txtName.AutoCompleteCustomSource = MySource
    txtName.AutoCompleteSource = AutoCompleteSource.CustomSource

    'Set List Box data back to the collection
    lbNames.DataSource = oContacts
    lbNames.DisplayMember = "FullName"

    lbNames.DrawMode = DrawMode.Normal
    lbNames.DrawMode = DrawMode.OwnerDrawVariable

End Sub