问题
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.
回答1:
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.
回答2:
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();
}
来源:https://stackoverflow.com/questions/7263227/display-busyindicator-in-wpf-application