2014-02-07 33 views
2

我正在主线程上执行一些繁重的计算,并且这些计算无法在单独的线程上运行。使用后台线程显示“Busy Indicator”

我想上的应用程序的用户界面显示一个“忙指示符”(即,纺丝插件)时这些计算都在运行。因此,我无法在主线程上显示忙碌指示符,因为在这些计算运行时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()没有任何反应,直到计算完成后,然后显示繁忙指示器。

我想从主线程进行通信,以具有繁忙指示符的线程。有没有人有办法?

+0

请提供一个原因,为什么这些操作无法在任何其他线程上运行,然后在UI线程?我没有看到任何实际的原因。 – ElGauchooo

+4

而不是在UI线程中执行非UI工作并在非UI线程中执行UI工作,将其逆转。您的用户界面是否在UI线程中工作,您的非UI工作是否在非UI线程中工作?这只是您使用的整个系统的设计。 – Servy

+0

我正在使用第三方库进行计算并检查调用者线程是否是主线程。所以我们不能改变他们的实现,所以我们必须在不同的线程上做我们的UI。 – Ahmed

回答

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

UI应该包含BusyIndicator控制将被激活/停止时,你会开始/结束工人。

+0

我正在使用第三方库进行计算并检查调用者线程是否是主线程。所以我们不能改变他们的实现,所以我们必须在不同的线程上做我们的UI – Ahmed

+0

@Ahmed你可以添加一些引用/链接或描述它是什么类型的库? –

-4

我得到这个从SO,但无法找到它的UI线程SO
运行这一点,并把你的任务,其中很长的任务是

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 
} 
+0

由于UI线程被阻塞,这将不会执行任何操作。 – Servy

+0

@Servy你测试了吗?我使用了很多。 – Paparazzi

+2

您经常在应用程序的UI线程中执行长时间运行的非UI操作?你不明白为什么这是一个坏主意? – Servy

1

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

所以你发现,因为它是忙你的长期运行的过程中,你不能显示你的UI线程在繁忙的指标......在这一点上,大多数开发人员会实现自己的错误,但不幸的是,不是你。而不是接受长时间运行的过程应该在后台线程上运行,而是做相反的事情,现在想要在后台线程中显示一些UI元素,同时用长时间运行的进程阻塞UI线程?

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

调用线程不能访问这个对象,因为不同的线程拥有它。

1

您需要调用busyContainer分派器。使用如下

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