Tsukasa
Tsukasa

Reputation: 6552

WPF ObservableCollection not updating?

Can't seem to get an ObservableCollection to update. The TreeView shows empty. Error: this type of collectionview does not support changes to its sourcecollection from a thread differentfrom the dispatcher thread.

Class level var

public ObservableCollection<TSItem> tsItems { get; set; }

Initialize Components

tsItems = new ObservableCollection<TSItem>();
bwRun.DoWork += bwRun_DoWork;
InitializeComponent();
tvTest.ItemsSource = tsItems;

from the background worker I use the following method to add to the collection

 private void AddTreeViewItem(TSItem item)
 {
     tsItems.Add(item);
 }

xaml

<TreeView x:Name="tvTest" HorizontalAlignment="Left" Height="249" Margin="140,36,0,0" VerticalAlignment="Top" Width="257">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Image Source="{Binding Icon}" />
                    <TextBlock Text="{Binding Header}" />
                </StackPanel>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>

Upvotes: 1

Views: 1273

Answers (3)

Gusdor
Gusdor

Reputation: 14334

You have to invoke back onto the UI thread before updating your observable collection.

As a shortcut to just get it working, consider Application.Dispatcher.Invoke or BeginInvoke.This requires a reference to PresentationCore so may not be great for MVVM if you want to be super pure about it.


If you want to be purer one way or another, you need to do a bit more work. Most of this involves trapping the SynchronizationContext of the UI thread.

  • Create your own implementation of INotifyCollectionChanged that wraps a SynchronizationContext and forwards the events of an internal ObservableCollection
  • Grab the SynchronizationContext in your constructor using SynchronizationContext.Current. This only works if your constructor is accessed on the UI thread.
  • Pass a SynchronizationContext into every class that needs ones.

Upvotes: 3

Somedust
Somedust

Reputation: 1170

You should dispatch changes to UI thread:

 private void AddTreeViewItem(TSItem item)
 {
    Dispatcher.BeginInvoke(new Action(() => tsItems.Add(item)));
 }

Upvotes: 3

stevethethread
stevethethread

Reputation: 2524

@Somedust is correct. I would also add that you say that you are updating the observable collection via the background worker. If you are doing that, you need to ensure that you are back on the UI thread when doing so.

Upvotes: 1

Related Questions