c# - 使用后台线程显示 "Busy Indicator"

标签 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() 直到计算完成之后才会发生任何事情,然后显示繁忙指示器。

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

最佳答案

没有理由在 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();

UI 应包含 BusyIndi​​cator 控件,当您启动/完成工作人员时,该控件将激活/停止

关于c# - 使用后台线程显示 "Busy Indicator",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21630834/

相关文章:

c# - WPF:ListView 和编辑 ListViewItem

wpf - Silverlight:层次结构 TreeView 的自定义模板

python - 为什么这种递归不会超出递归限制

java - (线程新手)构建即时消息应用程序的最佳方式?

c# - LINQ:C# 中 XML 节点的求和值

c# - 从内存中加载数据库文件

wpf - XAML 子类类型声明设计器错误

javascript - 使用线程 - UbuntuTouch/QML/Javascript

c# - 消息 : Invalid JSON primitive: ajax jquery method with Webmethod

c# - 使用对象数据填充 GridView