3

I have problems, updating a WPF ListView Bound to a an ObservableCollection<T> within an Task Thread using (Task Parallel Library)

I have an Small Tool reading Edifact Files, and displaying an Count of each Segment (first three letters of a Line).

The contained Segments with their Counts are displayed in an Listbox.

Wenn I initially Load a File all works fine, and I see the GUI Counting up the Segments. My Programm allowed switching to another File, If I do that (using exactly the same Code) it failes with the following Exception.

This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.

Here is the Code that fails

public class SegementLineCollection : ObservableCollection<SegmentLine>
  {
    public void IncrementCount(string Segment)
    {
      Segment = Segment.ToUpper();

      SegmentLine line;
      if (this.Select(x => x.SegmentName).Contains(Segment))
      {
        line = this.Where(x => x.SegmentName == Segment).FirstOrDefault();
      }
      else
      {
        line = new SegmentLine();
        line.SegmentName = Segment;

        this.Add(line); // <--- At this point comes the Exception
      }

      line.Count++;
    }
  }

Here is the TPL Call I use:

private string _FileName;
    public string FileName
    {
      get
      {
        return _FileName;
      }
      set
      {
        _FileName = value;
        OnPropertyChanged("FileName");

        if (!String.IsNullOrEmpty(value)) 
          new Task(() => StartFile()).Start();
      }
    }

Does anyone have any hit for me?

------------ E D I T ------------------

The provided Answers using TaskScheduler.FromCurrentSynchronizationContext() or Dispatcher did not do the Trick!

Is it possible that changing the Binding when loading the new does the trick.

Here is the Binding I use, the Reader Onject is Switched in the ViewModel, and the GUI is Notfied with INotifyPropertyChanged implementation

Cœur
  • 37,241
  • 25
  • 195
  • 267
sebastianmehler
  • 1,033
  • 1
  • 11
  • 23
  • 1
    Duplicate of http://stackoverflow.com/questions/3628477/update-a-observablecollection-with-a-background-worker-in-mvvm – Matten Apr 24 '12 at 06:54
  • Did you even read the message of the exception? It tells you exactly what is wrong. – svick Apr 24 '12 at 07:06
  • 1
    Svick, he read it, but he's not asking for the question but for a solution. BTW, why does this work the first time around? Shouldn't that cause the same exception? – Sebastian Edelmeier Apr 24 '12 at 07:24
  • @svick: sure I read the Exception Message, and saw that this is an Threading Issue. If I knew an answer I would not ask. – sebastianmehler Apr 24 '12 at 07:32

4 Answers4

1

Use a dispatcher to access the collection:

if (Dispatcher.CurrentDispatcher.CheckAccess())
  this.Add(...)
else
  Dispatcher.CurrentDispatcher.Invoke(() => this.Add(...));
Matten
  • 17,365
  • 2
  • 42
  • 64
1

You need to call IncrementCount on the GUI thread.

With TPL you can use TaskScheduler.FromCurrentSynchroniztionContext() in your task or continuation.

var task = new Task<string>(() => { return "segment"; })
var task2 = task.ContinueWith(t => IncrementCount(t.Result),
                              TaskScheduler.FromCurrentSynchroniztionContext());
task.Start();
adrianm
  • 14,468
  • 5
  • 55
  • 102
0

As you are acting on different thread you need to use Dispatcher.BeginInvoke to run an updates on a collection bound to UI

Tigran
  • 61,654
  • 8
  • 86
  • 123
-2

I have a solution for this kind of problems in the following blog..

http://bathinenivenkatesh.blogspot.co.uk/2011/07/wpf-build-more-responsive-ui.html

it got detailed explanation and code snippets...

Bathineni
  • 3,436
  • 18
  • 25