2009-06-10 29 views
0

Ich habe versucht, den Dispatcher in einen Thread zu wickeln. Aber das Ergebnis ist nicht das, was ich erwarte. Wie kann ich dieses Problem lösen?WPF-Dispatcher und Ausführen im Hintergrund

public void Start() 
    { 
     ThreadStart ts = inner; 
     Thread wrapper = new Thread(ts); 
     wrapper.Start(); 
    } 

    private void inner() 
    { 
     _Runner.Dispatcher.Invoke(_Runner.Action, DispatcherPriority.Normal); 
    } 
+2

Was ist das Ergebnis und was Sie erwarten –

+0

Erwartung: Dispatcher und es im Hintergrund auch versucht BeginInvoke Laufen. Das Ergebnis ist das gleiche. Beim Start vom Client aufgerufen (Klick auf Button etc.) läuft und endet der Thread. Aber der Client kann nichts tun, während der Prozess läuft. –

Antwort

5

Sie haben uns nicht genug Code gezeigt/erklären Sie sich gut genug, um eine gute Antwort zu geben, aber ich bin raten Ihre Aktion (_Runner.Action) ist teuer und langsam auszuführen. Wenn dies der Fall ist, reagiert Ihre Benutzeroberfläche nicht mehr. Sie weisen den Dispatcher im Wesentlichen an, diesen teuren Vorgang auf dem Benutzeroberflächenthread auszuführen, wenn Sie so viel wie möglich im Hintergrundthread ausführen möchten, und dann nur dann zurück zum Benutzeroberflächenthread über die wenn notwendig.

+0

Meine Gedanken genau. –

+0

Der Hintergrundthread hilft nicht, wenn er den Dispatcher sofort dazu aufruft, die Aufgabe im UI-Thread auszuführen. –

2

Wenn Sie eine Aktion über/auf dem Dispatcher auslösen, wird diese Aktion im UI-Thread aufgerufen.

Meine Vermutung ist, dass Sie die Arbeit/Verarbeitung in der _Runner.Action Funktion tun und es bindet den UI-Thread. Sie müssen den Hauptverarbeitungsteil in der Funktion inner() ausführen und dann den Dispatcher für die letzten Aktualisierungsdetails aufrufen.

Wenn Sie unbedingt auf dem Dispatcher verarbeiten müssen, brechen Sie Ihren Prozess in kleinere Stücke und rufen Dispatcher.BeginInvoke() für jedes Stück auf, damit andere Ereignisse zwischen Ihrem Prozess verarbeitet werden können.

0

Ja. _Runner.Action ist das Problem. Einige zeitgesteuerte Methoden, die im Dispatcher-Block verwendet werden. Lösung: "Verwenden Sie keinen Thread, der nicht mit der Benutzeroberfläche im Dispatcher verknüpft ist"

1

Hier ein Beispiel, in dem Sie WPF-Anwendungen mit mehreren UI-Threads ausführen können. Ich glaube, das wird dir helfen. Siehe diesen http://eprystupa.wordpress.com/2008/07/28/running-wpf-application-with-multiple-ui-threads/

Thread lThread = new Thread(() => 
        { 
         var lWnd = new Window1(); 
         lWnd.Show(); 
         lWnd.Closed += (sender2, e2) => lWnd.Dispatcher.InvokeShutdown(); 
         System.Windows.Threading.Dispatcher.Run(); 
        }); 
lThread.SetApartmentState(ApartmentState.STA); 
lThread.Start(); 
2

Sie müssen Runner.Action in zwei Teile brechen - der Langlaufteil, der in die Berechnung und den Teil, der die GUI aktualisiert.

Nachdem Sie dies getan haben, rufen Sie den lang laufenden Teil im Hintergrund-Thread und verwenden Sie den Dispatcher nur auf dem UI-Update-Teil.

Übrigens sollten Sie auch BeginInvoke und nicht Invoke verwenden.

Wenn der lange laufende Teil von Runner.Action die GUI aktualisiert, können Sie keinen Hintergrundthread verwenden, um Ihr Problem zu lösen. Es gibt Lösungen für langsame GUI-Operationen, aber sie ändern sich je nachdem, was genau Sie versuchen .

1

Dito, was jeder hier gesagt hat.

Darüber hinaus möchten Sie möglicherweise in der Verwendung der BackgroundWorker Klasse zu untersuchen.

1

Dies ist, was ich für Hintergrundaufgaben verwendet habe ... Ich habe es nicht lange verwendet, also weiß ich nicht, ob es Fehler gibt.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace SSA.Utility 
{ 
    public class BackgroundTaskManager : IDisposable 
    { 
     private System.Windows.Threading.Dispatcher _OwnerDispatcher; 
     private System.Windows.Threading.Dispatcher _WorkerDispatcher; 
     private System.Threading.Thread _WorkerThread; 
     private Boolean _WorkerBusy; 

     private System.Threading.EventWaitHandle _WorkerStarted = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.ManualReset); 

     public BackgroundTaskManager() 
     { 
      _OwnerDispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher; 
      _WorkerThread = new System.Threading.Thread(new System.Threading.ThreadStart(WorkerStart)); 
      _WorkerThread.Name = "BackgroundTaskManager:" + DateTime.Now.Ticks.ToString(); 
      _WorkerThread.IsBackground = true; 
      _WorkerThread.Start(); 

      _WorkerStarted.WaitOne(); 
     } 

     public Boolean IsBusy 
     { 
      get { return _WorkerBusy; } 
     } 

     public System.Windows.Threading.Dispatcher Dispatcher 
     { 
      get { 
       return _WorkerDispatcher; 
      } 
     } 

     public System.Windows.Threading.Dispatcher OwnerDispatcher 
     { 
      get 
      { 
       return _OwnerDispatcher; 
      } 
     } 


     private void WorkerStart() 
     { 
      _WorkerDispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher; 
      _WorkerDispatcher.Hooks.DispatcherInactive += WorkDone; 
      _WorkerDispatcher.Hooks.OperationPosted += WorkAdded; 
      _WorkerStarted.Set(); 
      System.Windows.Threading.Dispatcher.Run(); 
     } 

     private void WorkAdded(Object sender, System.Windows.Threading.DispatcherHookEventArgs e) 
     { 
      _WorkerBusy = true; 
     } 

     private void WorkDone(Object sender, EventArgs e) 
     { 
      _WorkerBusy = false; 
     } 

     public void Dispose() 
     { 
      if (_WorkerDispatcher != null) 
      { 
       _WorkerDispatcher.InvokeShutdown(); 
       _WorkerDispatcher = null; 
      } 
     } 

    } 
} 


// Useage (not tested) 

private SSA.Utility.BackgroundTaskManager _background = new SSA.Utility.BackgroundTaskManager(); 

public void LongTaskAsync() 
{ 
    _background.Dispatcher.BeginInvoke(new Action(LongTask), null); 
} 

public void LongTask() 
{ 
    System.Threading.Thread.Sleep(10000); // simulate a long task 
    _background.OwnerDispatcher.BeginInvoke(new Action<STATUSCLASS>(LongTaskUpdate), statusobject); 
} 

public void LongTaskUpdate(STATUSCLASS statusobject) { 

} 
+1

Dies scheint eine wirklich komplizierte Art zu sein, eine Hintergrundaufgabe zu erstellen. Ich würde BackgroundWorker verwenden. http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx – evanb

+0

Ich gebe zu, es ist Overkill für die meisten Dinge, aber ich mag, dass die Syntax, um es zu verwenden ist identisch mit dem normalen Dispatcher und ich mag das Prioritätsmerkmal. Ich verwende es für eine Reihe von Arbeitsaufgaben anstelle einer einzelnen Aktion. BackgroundWorker hat dafür keine eingebaute Funktion. Die ursprüngliche Frage war über Dispatcher in einem neuen Thread, der dies implementiert. – DanielHac

+0

Wenn Sie unsere Essenz Ihrer Antwort trennen könnten und vielleicht eine Ratschläge für nützliche Ergänzungen teilen, wäre die Antwort viel besser. Danke für das Teilen und herzlich willkommen bei SO! –

Verwandte Themen