2014-02-07 73 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 
        }));