在STA线程上显示忙指示符

我有一个很长的操作,我想展示Extended Toolkits忙指示器。 我之前发过一篇关于此的post,修复了Wpf Extended toolkit BusyIndi​​cator在操作期间没有显示的问题 。 但是,在该调用期间,我必须与UI元素(canvas)进行交互,并且我得到“调用线程必须是STA,因为许多UI组件需要这个”。 我理解(现在)后台工作者(见代码):

private void CboItemId_SelectionChanged(object sender, SelectionChangedEventArgs e) { BackgroundWorker _backgroundWorker = new BackgroundWorker(); _backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork); _backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_backgroundWorker_RunWorkerCompleted); ItemSearchBusyIndicator.IsBusy = true; // Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait; if (RdoItemSearch.IsChecked == false) return; ///backgroundWorker_DoWork(null, null); if (CboItemId.SelectedValue == null) return; if (CboItemId.SelectedValue.ToString() != string.Empty) { selectedItem = CboItemId.SelectedValue.ToString(); _backgroundWorker.RunWorkerAsync(); } // Mouse.OverrideCursor = System.Windows.Input.Cursors.Arrow; } public void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { LoadItemData(selectedItem); } 

使用MTA,不能设置为STA。 所以我尝试在自己的线程中调用使用UI元素的内部函数:

  public void LoadItemData(string itemId) { Axapta ax = new Axapta(); files.Clear(); try { ax.Logon(Settings.Default.Server, null, Settings.Default.Test, null); AxaptaContainer path = (AxaptaContainer)ax.CallStaticClassMethod(Settings.Default.ClassName, Settings.Default.ItemData, itemId); for (int i = 1; i <= path.Count; i++) { AxaptaContainer somestring = (AxaptaContainer)path.get_Item(i); for (int j = 1; j <= somestring.Count; j += 2) { string extension = Path.GetExtension(somestring.get_Item(j + 1).ToString().ToLower()); if (extension == ".jpg" || extension == ".jpeg" || extension == ".gif" || extension == ".png" || extension == ".bmp" || extension == ".pdf") /* key=path - value=description */ files.Add(somestring.get_Item(j + 1).ToString(), somestring.get_Item(j).ToString()); } } // _canvas.Children.Clear(); Thread t = new Thread(new ThreadStart(LoadPictures)); t.SetApartmentState(ApartmentState.STA); t.Start(); } catch (Exception ex) { MessageBox.Show(ex.Message); } finally { ax.Logoff(); } } 

inheritance我与canvas元素交互的地方:

  private void LoadPictures() { foreach (DictionaryEntry filePath in files) { try { Picture p = new Picture(); ToolTip t = new ToolTip(); t.Content = filePath.Value; p.ToolTip = t; TextBlock tb = new TextBlock(); tb.Text = filePath.Value.ToString(); Canvas.SetTop(tb, y); Canvas.SetLeft(tb, x); p.ImagePath = filePath.Key.ToString(); p.OriginalImagePath = filePath.Key.ToString(); p.ImageName = filePath.Value.ToString(); _canvas.Children.Add(p); //<-------This is where i seem to error } catch (Exception ex) { MessageBox.Show("Error:" + ex.Message,"File Load Error",MessageBoxButton.OK,MessageBoxImage.Error); } } } 

但我得到一个“调用线程无法访问此对象,因为另一个线程拥有它”我不知道如何在没有后台工作者的情况下显示BusyIndi​​cator时调用长时间运行(LoadItemData())函数。 任何帮助赞赏

有多种方法:

1) 异步绑定 ,不推荐,但它存在。 你可以在属性getter中运行长时间运行的任务,框架将阻止UI阻塞,当它完成时 – UI将得到更新。

2)使用BackgroundWorkerTask / Thread来运行代码,但将其调用到UI线程中。 在你的例子中:

 Dispatcher.InvokeAsync(() => _canvas.Children.Add(p)); 

3)您可以完全阻止主窗口的UI线程,没有问题。 但是为了表明它正忙,你可以在另一个线程中创建窗口并显示忙状态(运行动画等):

  var thread = new Thread(() => { var window = new SomeWindow(); window.ShowDialog(); }); thread.SetApartmentState(ApartmentState.STA); thread.IsBackground = true; thread.Start();