【问题标题】:Display busyindicator in wpf application在 wpf 应用程序中显示忙指示符
【发布时间】:2011-11-07 23:01:06
【问题描述】:

我有一个来自 wpf 扩展工具包的 BusyIndi​​cator,我正在运行一个需要一段时间才能完成的函数。如果我在单独的线程中运行耗时的任务,我会收到 NotSupportedException,因为我正在尝试将对象从那个不同的线程插入到 ObservableCollection 中。如果可能的话,我真的不想花很多时间重构代码......有没有办法可以在单独的线程中设置指示器的可见性?

编辑

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

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

这对我也不起作用。

【问题讨论】:

  • 我编辑了我的答案,为您提供解决方案。

标签: wpf multithreading busyindicator


【解决方案1】:

您应该可以使用Dispatcher 来处理类似的事情。例如

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

这将导致代码在 UI 线程上运行。

threading model reference 中有更多信息(包括如何“正确”执行此操作,使用 CheckAccess 等)。

【讨论】:

  • 这不起作用...繁忙指示器不可见:System.Windows.Application.Current.Dispatcher.Invoke((Action)(() => { IsBusy = true; })); functionThatTakesForever(); System.Windows.Application.Current.Dispatcher.Invoke((Action)(() => { IsBusy = false; })); 我在 ViewModel 中而不是在代码隐藏中执行这些操作这一事实是否会对它的行为方式?
  • @drowned:你在不同的线程上运行它,对吧?如果你不这样做,UI 仍然会阻塞。每当您需要访问 UI 线程拥有的元素(包括您的 ObservableCollection)时,请在后台线程中使用调度程序。
  • 也许我误解了......我会更新我的问题以反映我试图做的事情。
  • 长时间运行的函数当然也需要在后台线程上执行。否则整个事情都是没有意义的,如果你只是设置 IsBusy 你就不需要一个线程。
  • 但是当我这样做时,尝试插入集合时出现异常
【解决方案2】:

您无法从后台工作人员访问 UI 控件。您通常所做的是在调用 BackgroundWorker.RunWorkerAync() 之前将 IsBusy 设置为 true,然后在 BackgroundWorker.RunWorkerCompleted 事件处理程序中将 IsBusy 设置为 false。类似于:

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

您可以在 DoWork 事件处理程序中使用 Dispatcher 将项目添加到 ObservableCollection。

编辑:这是完整的解决方案

        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();      
    }

【讨论】:

  • 这是我尝试的第一件事。尝试插入集合时遇到同样的异常。
  • @H.B.即使您不使用 BackgroundWorker,这些概念也是相同的。
猜你喜欢
  • 2014-10-04
  • 1970-01-01
  • 1970-01-01
  • 2015-08-04
  • 1970-01-01
  • 2014-11-18
  • 2015-02-24
  • 2015-07-31
  • 2011-09-11
相关资源
最近更新 更多