How to ensure a list box is updated when properties of item VMs are updated?

Developer
Jul 4, 2011 at 9:55 PM

I should know the answer by now, but I by brain's not cooperating today. I have a ListBox bound to a filtered list...

<ListBox x:Name="objectList" ItemsSource="{Binding FilteredList}" SelectionMode="Extended">
And FilteredList returns a list of objects defined like so...

_filteredList = new DependentList<ObjectViewModel>(() => 
from o in _completeList.Value where !IsFilteredOut(o) select new ObjectViewModel(o,...));
When the set of items changes, the list is updated, but not when a property changes that determines the appearance of a list item (currently ToString() is called to get the item text). ToString() in the viewmodel reads properties of the model, which are guarded by an Independent sentry.

How do I get the list box text to update when these properties change?

(note: I am still maintaining a WinForms view and it has the same problem.)

Coordinator
Jul 4, 2011 at 11:24 PM

There is no mechanism for firing property changed events for ToString(). For the XAML ListBox, the solution is to define an ItemsTemplate that binds a TextBlock to a string property of your items. Update Controls can then manage the dependency of that property.

For the Windows Forms version, you should only need to handle the GetItemText event. Cast the parameter to ObjectViewModel, and calculate the text.

One last thing. Make sure that you implement Equals and GetHashCode on ObjectViewModel. Strange things can happen if you don't. I don't know if that's the cause of this issue, but it could be.

Hope this helps.

Developer
Jul 4, 2011 at 11:40 PM
Edited Jul 4, 2011 at 11:45 PM

Okay, I added a VM property...

public string SummaryString { get { return ToString(); } }

and DataTemplate...

<ListBox.ItemTemplate>
    <DataTemplate>
        <TextBlock Text="{Binding Path=SummaryString}"/>
    </DataTemplate>
</ListBox.ItemTemplate>

And the problem is solved in WPF. Thanks! However, adding a GetItemText handler for WinForms doesn't help:

private string _objectList_GetItemText(object tag)
{
	return tag.ToString();
}

(this of course is the same as calling SummaryString.) The ViewModel and Model code is shared between WPF and WinForms. Any ideas? (note: I have implemented Equals and GetHashCode as usual on the VM.)

Coordinator
Jul 5, 2011 at 4:04 AM

After revisiting the code, I think I see why it isn't working in Windows Forms. ListBoxItem will start returning the new value from ToString(), but nothing tells the ListBox to refresh. I can think of two ways to fix this.

First, ListBoxItem could remove and replaced itself when the text changes. That should trigger a refresh. But it might mess with scrolling and selection.

Second, the UpdateListBox could have a dependent that touches the text of all items. When it updates, it could trigger a repaint. I'm not sure if this would work.

I'll try to get some time this week to look into it. In the meantime, you might want to try UpdateListView instead. I don't think it has the same problem.

Developer
Jul 5, 2011 at 7:23 PM

Yeah, a dependent associated with the text of all the items makes sense. And I suppose just calling Refresh() is enough to see new labels in WinForms.