2014-02-07 2 views
2

주 스레드에서 많은 계산을하고 있으며 이러한 계산은 별도의 스레드에서 실행할 수 없습니다.백그라운드 스레드를 사용하여 "Busy Indicator"를 표시합니다.

계산이 실행 중일 때 애플리케이션 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() 아무것도 계산의 종료 후까지 발생하지 후 바쁜 표시기가 표시됩니다와

.

메인 스레드에서 통화 중 표시기가있는 스레드로 통신하고 싶습니다. 누구나 접근 할 수 있습니까?

+0

다른 스레드에서 이러한 작업을 실행할 수없는 이유를 입력하십시오. 실용적인 이유는 없습니다. – ElGauchooo

+4

UI 스레드에서 비 UI 작업을 수행하고 비 UI 스레드에서 UI 작업을 수행하는 대신 역순으로 처리하십시오. UI 스레드는 UI 스레드에서 작동하고 비 UI UI는 비 UI 스레드에서 작동합니까? 이는 단순히 사용중인 전체 시스템의 디자인 일뿐입니다. – Servy

+0

해당 계산 및 호출자 스레드가 주 스레드로 확인하는 타사 라이브러리를 사용하고 있습니다. 따라서 UI를 다른 스레드에서 수행해야하므로 구현을 변경할 수 없습니다. – Ahmed

답변

4

UI 스레드에서 "과도한 계산"을 실행할 이유가 없습니다. 더군다나 이것은 나쁜 습관입니다. 대신 그동안 살아 UI 스레드가 계산 로드/표시됩니다, 일을 할 BackgroundWorker를 사용 : 시작 것이다 때/을 완료

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 
        })); 
관련 문제