Listbox does not display the changes made to an object

A

Academia

(If you've seen this in the drawing NG, sorry. I inadvertently sent it
there.)


I have a listbox populated with Objects.

The Class has a String field that ToString returns.

I assume that is what the ListBox uses for its display. Correct?

If I change the value of the object's string field the ListBox display does
not change. Would you expect it to change?

The Debugger shows that the item does in fact have the new value even though
the display has not changed.

I tried putting
ListBox1.SuspendLayout() and ListBox1.ResumeLayout() around the change code
to see it by chance that would trigger a change in display but it didn't. I
didn't really expect it would.

So I added code to remove and then add the item:

Dim j As Object = ListBox1.Items(ListBox1.SelectedIndex)

Dim i As Integer = ListBox1.SelectedIndex

ListBox1.Items.RemoveAt(i)

ListBox1.Items.Insert(i, j)

ListBox1.SelectedIndex = i



That works. Now as soon as the Object is changed the new value displays.

But I can't say I like it.

Isn't there a better way?



Thanks for any help



PS The ListBox appears to generate a list of strings so that it does not
have to access the objects when a Paint is required? Is that your
understanding?
 
R

rowe_newsgroups

(If you've seen this in the drawing NG, sorry. I inadvertently sent it
there.)

I have a listbox populated with Objects.

The Class has a String field that ToString returns.

I assume that is what the ListBox uses for its display. Correct?

If I change the value of the object's string field the ListBox display does
not change. Would you expect it to change?

The Debugger shows that the item does in fact have the new value even though
the display has not changed.

I tried putting
ListBox1.SuspendLayout() and ListBox1.ResumeLayout() around the change code
to see it by chance that would trigger a change in display but it didn't. I
didn't really expect it would.

So I added code to remove and then add the item:

Dim j As Object = ListBox1.Items(ListBox1.SelectedIndex)

Dim i As Integer = ListBox1.SelectedIndex

ListBox1.Items.RemoveAt(i)

ListBox1.Items.Insert(i, j)

ListBox1.SelectedIndex = i

That works. Now as soon as the Object is changed the new value displays.

But I can't say I like it.

Isn't there a better way?

Thanks for any help

PS The ListBox appears to generate a list of strings so that it does not
have to access the objects when a Paint is required? Is that your
understanding?

Will a call to ListBox.Refresh() or ListBox.Invalidate() work?

Thanks,

Seth Rowe
 
J

Jack Jackson

(If you've seen this in the drawing NG, sorry. I inadvertently sent it
there.)


I have a listbox populated with Objects.

The Class has a String field that ToString returns.

I assume that is what the ListBox uses for its display. Correct?

If I change the value of the object's string field the ListBox display does
not change. Would you expect it to change?

The Debugger shows that the item does in fact have the new value even though
the display has not changed.

I tried putting
ListBox1.SuspendLayout() and ListBox1.ResumeLayout() around the change code
to see it by chance that would trigger a change in display but it didn't. I
didn't really expect it would.

So I added code to remove and then add the item:

Dim j As Object = ListBox1.Items(ListBox1.SelectedIndex)

Dim i As Integer = ListBox1.SelectedIndex

ListBox1.Items.RemoveAt(i)

ListBox1.Items.Insert(i, j)

ListBox1.SelectedIndex = i

That works. Now as soon as the Object is changed the new value displays.

But I can't say I like it.

Isn't there a better way?

Thanks for any help

PS The ListBox appears to generate a list of strings so that it does not
have to access the objects when a Paint is required? Is that your
understanding?

I think that if the Object implements INotifyPropertyChanged that will
fix it. If you Google for that you can find some examples of how to
use it.

I have no idea about the Paint questions.
 
R

rowe_newsgroups

I think that if the Object implements INotifyPropertyChanged that will
fix it. If you Google for that you can find some examples of how to
use it.

I have no idea about the Paint questions.

Hmm, just tried a few things to no avail, and then tried the
INotifyPropertyChanged interface you mentioned, but no dice. I
unfortunately don't know of a way to force a complete refresh without
reloading the effected item(s).

Here's the code I used if anyone wants to build on my efforts (just
paste into a new form's codebehind)

/////////////////////
Imports System.ComponentModel

Public Class Form1

Private listBox As ListBox
Private button As Button

Private listBoxItems As List(Of ListBoxItem)

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
'// Load the ListBox
listBox = New ListBox()
Controls.Add(listBox)

'// Add an event to track if the values change
AddHandler listBox.SelectedIndexChanged, AddressOf
listBox_SelectedIndexChanged

'// Add some custom items to our listBoxItems
listBoxItems = New List(Of ListBoxItem)

For i As Integer = 0 To 9
listBoxItems.Add(New ListBoxItem(String.Format("Item {0}",
i.ToString()), i))
Next

'// Add them to our ListBox
listBox.Items.AddRange(listBoxItems.ToArray())

'// Load the Button
button = New Button()
button.Text = "Click Me"
button.Location = New Point(150, 10)
Controls.Add(button)

'// Map the Button's click event
AddHandler button.Click, AddressOf button_Click
End Sub

Private Sub listBox_SelectedIndexChanged(ByVal sender As Object,
ByVal e As EventArgs)
Dim item As ListBoxItem = DirectCast(listBox.SelectedItem,
ListBoxItem)
MessageBox.Show(String.Format("{0}, {1}", item.Text,
item.Value))
End Sub

Private Sub button_Click(ByVal sender As Object, ByVal e As
EventArgs)
'// Modify the listBoxItems
For Each item As ListBoxItem In listBoxItems
item.Value += 1
item.Text = String.Format("Item {0}",
item.Value.ToString())
Next

listBox.Update()
End Sub

End Class

Public Class ListBoxItem
Implements INotifyPropertyChanged

Public Sub New(ByVal text As String, ByVal value As Integer)
Me.Text = text
Me.Value = value
End Sub

Public Overrides Function ToString() As String
Return Text
End Function

Public Property Value() As Integer
Get
Return _Value
End Get
Set(ByVal value As Integer)
_Value = value

RaiseEvent PropertyChanged(Me, New
PropertyChangedEventArgs("Value"))
End Set
End Property
Private _Value As Integer = 0

Public Property Text() As String
Get
Return _Text
End Get
Set(ByVal value As String)
_Text = value

RaiseEvent PropertyChanged(Me, New
PropertyChangedEventArgs("Text"))
End Set
End Property
Private _Text As String = String.Empty

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

Thanks,

Seth Rowe
 
G

Guest

I was able to take your example and a slightly different approach and get the
behavior you were looking for. Instead of using a list, I used a
BindlingList and instead of listBox.Items.AddRange(listBoxItems.ToArray())
I had
listBox.DataSource = listBoxItems
The difference (I think) is that the BindingList looks for the
PropertyChanged event and raises a 'ListChanged' event, that the ListBox
looks for.
One thing that happened that I don't understand was that when the button was
clicked, and the items were changed, the SelectedIndexChanged event was
fired! And on the second change (second item in the list) the event was
fired, but the selecteditem was 'Nothing'. I had to comment out the code in
the routine to get it to work.
 

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