A better way of forcing data bound WPF ListBox to update?
Asked Answered
M

8

34

I have WPF ListBox which is bound to a ObservableCollection, when the collection changes, all items update their position.

The new position is stored in the collection but the UI does not update. So I added the following:

    void scenarioItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        ToolboxListItem.UpdatePositions();
        lstScenario.ItemsSource = null;
        lstScenario.ItemsSource = ToolboxListItem.ScenarioItems;
        this.lstScenario.SelectedIndex = e.NewStartingIndex;
    }

By setting the ItemsSource to null and then binding it again, the UI is updated,

but this is probably very bad coding :p

Suggestions?

Mccrory answered 31/10, 2008 at 10:16 Comment(1)
Can you please give more detail on what you mean by "when the collection changes, all items update their position", just so I can be sure I am answering your question properly?Heinrich
L
79

I have a Listbox bound to an object property which is of type List<MyCustomType>() and I verified that the following code updates the listbox when the List is updated.

void On_MyObjProperty_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
   MyListBox.Items.Refresh();
}

If you're still facing issues, scan the VS IDE output window (Ctrl+W, O) and see if you can spot any binding errors reported.

Lhary answered 31/10, 2008 at 12:15 Comment(4)
This does seem to solve the problem, so I'll move the bug question into another post. Thank you!Mccrory
It's been over two years since someone commented on this... Thank you so much!Brother
If the ListBox is binded to a public property "MyItems" and the class with tihs property implements INotifyPropertyChanged, why not just raise the event PropertyChanged(this, "MyItems")? It will notify the UI the this object has changed and update automatically its values.Mccarter
@Mccarter This solution worked for my situation. In my situation the listbox's ItemsSource was databound to an ObservableCollection<BusinessObject>. When BusinessObject.SomeProperty was changed, the list did not reflect that change because BusinessObject was still the same instance (so no notification). The above refresh method caused the list to reevaluate the bindings/converter outputs.Harberd
M
11

WPF binding a list / collection of items to a ListBox, but UI not refreshing after items updated, Solved.

I'm just stupid. While I'd read a lot about using ObservableCollection<> instead of List<>, I just continued to ignore this suggestion and went following other suggestions, to no avail. Got back to my books and reread. It's pretty well explained that ObservableCollection<> is a must use because List<> doesn't provide the INotifyCollectionChange interface needed for the ListBox to update its display when the items change in the collection.

This is the updated code:

private ObservableCollection<StringWrapper> m_AppLog;
ObservableCollection<StringWrapper> Log { get { return m_AppLog; } }

Pretty simple, and doesn't require anything else (e.g. Refresh()). Because ObservableCollection takes care itself of triggering the change event, I was able to remove the unnecessary call:

// notify bound objects
OnPropertyChanged("Log");

ObservableCollection doesn't support an update by a thread which didn't create it. Because my list (a visual log to show the recent errors/info messages) can be updated from different threads, I add to adjust my code this way to ensure the update was done with the list's own dispatcher:

public void AddToLog(string message) {
    if (Thread.CurrentThread != Dispatcher.Thread) {
        // Need for invoke if called from a different thread
        Dispatcher.Invoke(
            DispatcherPriority.Normal, (ThreadStart)delegate() { AddToLog(message); });
    }
    else {
        // add this line at the top of the log
        m_AppLog.Insert(0, new StringWrapper(message));
        // ...

Also note that ObservableCollection<> doesn't support RemoveRange() contrary to List<>. This is part of the possible adjustments required when switching from List to ObservableCollection.

Mandalay answered 5/12, 2009 at 10:33 Comment(1)
I made this mistake also and it took a very long time before I found the solution. +1.Stockton
H
7

I may be having a similar problem to what you are having, but I'm not sure.

I had an ObservableCollection<MyEntity> and a ListBox bound to it. But for some strange reason my ListBox was not being updated when I changed the properties of the MyEntity objects in the list.

After searching for a while I found the following page and I just had to let you know:

http://www.wblum.org/listbind/net3/index.html

It is a very good description of what you have to do to get a ListBox to update when the list, or the objects within it, changes. Hoping you will benefit from this.

Howlond answered 9/11, 2010 at 21:55 Comment(2)
this is very great, thanks a lot! Especially that you just need to implement INotifyPropertyChanged for the class contained in the ListBox was interesting for me.Appointed
This domain is for sale.Abiosis
A
4

I had the same problem yesterday, and it's a complete piece of crap :) ... I'm not setting mine to null anymore though. In my scenario, I am setting it to MyList.ToArray() (after every time I add to the list).

I've seen multiple "oh, you need to use an ObservableList" <-- complete crap.

I've seen multiple "oh, call 'Refresh'" <-- complete crap.

Please forgive my upsettedness, but I also would expect this to work :)

Ashcraft answered 31/10, 2008 at 10:32 Comment(2)
Trust me, I can understand your frustration, so no offence taken. I have tried using GetBindingExpression but that retuls in a null :pMccrory
my "GetBindingExpression" doens't return null... but even if I call "UpdateTarget" it does nothing :( ... only in this case... it works great for everything else.Ashcraft
T
4

I know it's already a bit older but today I faced the same issue. I updated an property of an object inside an ObservableCollection and the View did not update, but then I found this awesome article.

I think it's a very clean solution to manually trigger the update of an ObservableCollection:

CollectionViewSource.GetDefaultView(this.myObservableCollection).Refresh();
Timikatiming answered 26/11, 2019 at 2:34 Comment(2)
Cool. This is the best answer for me.Yarndyed
This is what I did as well and it worked. It will even work if you have a regular list rather than an ObservableCollectionMartz
V
2

This is old stuff but, use an ObservableCollection. IF you want the UI to see updates to properties in the Objects of the ObservableCollection you need to implement INotifyPropertyChanged in the class defenition for that object. Then raise the property changed event in the setter of each property.

Public Class Session
Implements INotifyPropertyChanged

Public Event PropertyChanged As PropertyChangedEventHandler _
   Implements INotifyPropertyChanged.PropertyChanged

Private Sub NotifyPropertyChanged(ByVal info As String)
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub

Private _name As String = "No name"
''' <summary>
''' Name of Session
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Name() As String
    Get
        Return _name
    End Get
    Set(ByVal value As String)
        _name = value
        NotifyPropertyChanged("Name")
    End Set
End Property
Vd answered 13/4, 2010 at 15:14 Comment(0)
G
0

If you have an ObservableList of objects, and you're changing properties inside those objects, the notification doesn't apply since the collection is not changing directly. I have been forcing notification after changing my object properties by using Insert() to re-add my changed object to the collection, then RemoveAt() to remove the old copy. It's not pretty, but it works.

Grasping answered 26/4, 2009 at 2:12 Comment(0)
P
0

To me, it looks more like a bug in ListBox and ListView. I am binding to an ObservableCollection, the items in the collection implement INotifyPropertyChanged. The UI shows no added items when I dynamically press my 'add item' button however I have a counter control that is bound to MyCollection.Count. This counter control increments each time I press my 'add item' button. If I resize the view, the list box shows all my added items. So, the ItemSource binding on the ListBox control is broken. I also took care not to create a new MyCollection at any point, which would break the binding. Boo hoo.

Plata answered 10/10, 2014 at 16:5 Comment(1)
Lolz, in my situation, the problem was that someone actually implemented a class called ObservableCollection! So, my collection was not actually implementing INotifyCollectionChanged even though it was called ObservableCollection. Jeez. Once I removed the offending namespace, and used System.Collections.ObjectModel everything was fine. doh!Plata

© 2022 - 2024 — McMap. All rights reserved.