Question

I have a BusyIndicator from the wpf extended toolkit and I'm running a function that takes a while to complete. If I run the time consuming task in a separate thread, I get a NotSupportedException because I'm attemping to insert objects into an ObservableCollection from that different thread. I don't really want to spend a lot of time refactoring the code, if possible... Is there a way that I can set the visibility of the indicator in a separate thread instead?

EDIT

ThreadStart start = delegate()
  {
      System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
          {
              IsBusy = true;
          }));
   };

new Thread(start).Start();                                
longRunningFunction();

This did not work for me either.

Was it helpful?

Solution

You should be able to use the Dispatcher for things like that. e.g.

Application.Current.Dispatcher.Invoke((Action)(() =>
{
    _indicator.Visibility = Visibility.Visible;
}));

This will cause the code to be run on the UI-Thread.

There is more info (including how to "properly" do this, with CheckAccess and such) on it in the threading model reference.

OTHER TIPS

You cannot access UI controls from a background worker. What you normally do is set the IsBusy to true before you call BackgroundWorker.RunWorkerAync(), then in the BackgroundWorker.RunWorkerCompleted event handler you would set the IsBusy to false. Seomthing like:

Backgroundworker worker = new BackgroundWorker();
worker.DoWork += ...
worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
     IsBusy = false;
};
IsBusy = true;
worker.RunWorkerAsync();

You can use the Dispatcher to add items to your ObservableCollection while in the DoWork event hanlder.

EDIT: Here is the complete solution

        private void Button_Click(object sender, RoutedEventArgs e)
    {
        //on UI thread
        ObservableCollection<string> collection;

        ThreadStart start = delegate()
        {
            List<string> items = new List<string>();
            for (int i = 0; i < 5000000; i++)
            {
                items.Add(String.Format("Item {0}", i));
            }

            System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
            {
                //propogate items to UI
                collection = new ObservableCollection<string>(items);
                //hide indicator
                _indicator.IsBusy = false;
            }));
        };
        //show indicator before calling start
        _indicator.IsBusy = true;
        new Thread(start).Start();      
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top