使用后台线程显示“Busy Indicator”

时间:2014-02-07 14:55:29

标签: c# wpf multithreading

我正在主线程上进行一些繁重的计算,这些计算无法在单独的线程上运行。

我希望在运行这些计算时在应用程序UI上显示“忙碌指示符”(即旋转小部件)。因此,当这些计算正在运行时,由于UI被锁定,我无法在主线程上显示忙碌指示符。

要解决此问题,我尝试将忙指示符移动到单独的线程。在this post的帮助下,我可以将忙指示符放在单独的线程上。但是,我无法与此线程通信以启动或停止忙指示符。

     private HostVisual CreateBusyIndicatorOnWorkerThread()

    {
        // Create the HostVisual that will "contain" the VisualTarget
        // on the worker thread.
        HostVisual hostVisual = new HostVisual();
        Thread thread = new Thread(new ParameterizedThreadStart(BusyIndicatorWorkerThread));
        thread.ApartmentState = ApartmentState.STA;
        thread.IsBackground = true;
        thread.Start(hostVisual);
        // Wait for the worker thread to spin up and create the VisualTarget.
        s_event.WaitOne();
        return hostVisual;
    }

 private static AutoResetEvent s_event = new AutoResetEvent(false);
 private void BusyIndicatorWorkerThread(object arg)

    {
        // Create the VisualTargetPresentationSource and then signal the
        // calling thread, so that it can continue without waiting for us.
        HostVisual hostVisual = (HostVisual)arg;
        VisualTargetPresentationSource visualTargetPS = new VisualTargetPresentationSource(hostVisual);
        s_event.Set();

        // Create a MediaElement and use it as the root visual for the
        // VisualTarget.
        visualTargetPS.RootVisual = CreateBusyIndicator();

        // Run a dispatcher for this worker thread.  This is the central
        // processing loop for WPF.
        System.Windows.Threading.Dispatcher.Run();
    }

  private FrameworkElement CreateBusyIndicator()

    {
        var busyIndicator = new MyBusyIndicator();
        //busyIndicator.DataContext = this.
        Binding myBinding = new Binding("IsBusy");
        myBinding.Source = this;
        busyIndicator.SetBinding(MyBusyIndicator.IsBusyProperty, myBinding);
     }

我总是得到一个异常“调用线程无法访问此对象,因为另一个线程拥有它”。这是因为我正在尝试从主线程更新忙指示符,而忙指示符由另一个线程拥有。

我也试过this article

中给出的方法
private void CreateAndShowContent()
    {
        Dispatcher = Dispatcher.CurrentDispatcher;
        VisualTargetPresentationSource source =
            new VisualTargetPresentationSource(_hostVisual);
        _sync.Set();
        source.RootVisual = _createContent();
        DesiredSize = source.DesiredSize;
        _invalidateMeasure();

        Dispatcher.Run();
        source.Dispose();
    }

但是使用这种方法Dispatcher.Run()在完成计算之后才会发生任何事情,然后显示忙碌指示符。

我想从主线程到具有忙指示符的线程进行通信。有人有办法吗?

4 个答案:

答案 0 :(得分:4)

没有理由在UI线程中运行“繁重的计算”。更多 - 这是一个不好的做法。而是使用BackgroundWorker这将起作用,同时活着的UI线程将显示加载/计算

var worker = new BackgroundWorker();

worker.DoWork += (s, e) => {
   // This part will last at a separate thread without blocking UI.
   // Excellent place for heavy computations.
}

worker.RunWorkerCompleted += (s, e) => {
   // Here we're back to UI thread - so you can change states and stop animations.
}

// And finally start async computation
worker.RunWorkerAsync();

用户界面应该包含BusyIndicator控件,当启动/完成工作时,激活/停止

答案 1 :(得分:1)

请停止你正在做的事......这是完全错误的。 @Anatolii Gabuza是正确的......你不应使用UI线程任何长时间运行的进程,因为这会阻止它,使得应用程序在这些时候无法使用。除非你的长时间运行过程是渲染UI对象,否则确实有没有的理由使用UI线程...让我们知道它是什么,我们可以帮助你在后台运行它线程正确。

所以你发现你无法在UI线程上显示繁忙的指示器,因为它忙于你长时间运行的过程......此时,大多数开发人员会意识到他们的错误,但不幸的是,不是你。你不是接受长时间运行的进程应该在后台线程上运行,而是完全相反,现在想在后台线程中显示一些UI元素,同时用长时间运行的进程阻塞UI线程???

这真是疯狂,如果你想避免一些可怕的问题,请停止。如果你继续,那么你最好习惯看到那个例外:

  

调用线程无法访问此对象,因为另一个线程拥有它。

答案 2 :(得分:1)

您需要调用busyContainer调度程序。使用如下

this.busyContainer.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() =>
                    {
                        //update busy Container
                    }));

答案 3 :(得分:-4)

我从SO那里得到了这个,但是在SO上找不到它 在UI线程上运行此命令,并将任务放在任务很长的任务

public class WaitCursor : IDisposable
{
    private Cursor _previousCursor;

    public WaitCursor()
    {
        _previousCursor = Mouse.OverrideCursor;

        Mouse.OverrideCursor = Cursors.Wait;
    }

    #region IDisposable Members

    public void Dispose()
    {
        Mouse.OverrideCursor = _previousCursor;
    }

    #endregion
}

using (new WaitCursor())
{
    // very long task
}