Frage

Ich versuche, eine ObservableCollection zu aktualisieren, die an die UI gebunden ist, Daten. Ich weiß, dass dies Ich muß Gebrauch machen Dispatcher und BeginvInvoke(), und es so zu machen, dass die UI-up nicht einfrieren, wenn ich dies tun, indem ein Background ein guter Weg, um darüber zu gehen. Auf jeden Fall habe ich das alles, kompiliert und ausgeführt wird, aber nichts passiert. Ich brauche die Benutzeroberfläche alle 2 Minuten oder so zu aktualisieren, so dass ich auch eine DispatcherTimer

bin mit

Das funktioniert, weil DispatcherTimer Teil Dispatcher, sondern friert die Benutzeroberfläche:

DispatcherTimer dispTimer = new DispatcherTimer();
dispTimer.Tick += dispTimer_Tick;
dispTimer.Interval = new TimeSpan(0, 0, 45);
dispTimer.Start();

private void dispTimer_Tick(object sender, EventArgs e)
{
    PartialEmployees.Clear();          
}

Also, mit der Background ich zusammengestückelt folgt aus:

DispatcherTimer dispTimer = new DispatcherTimer();
dispTimer.Tick += dispTimer_Tick;
dispTimer.Interval = new TimeSpan(0, 0, 45);
dispTimer.Start();

private void dispTimer_Tick(object sender, EventArgs e)
{
    BackgroundWorker _worker = new BackgroundWorker();
    _worker.DoWork += DoWork;            
    _worker.RunWorkerAsync();

}

private void DoWork(object sender, DoWorkEventArgs e)
{            
    Dispatcher.CurrentDispatcher.BeginInvoke( new Action(()=> 
        {
            PartialEmployees.Clear();
        }));
} 

Aber nichts passiert mit der Benutzeroberfläche. Was mir fehlt / nicht richtig zu tun?

War es hilfreich?

Lösung

Sie haben zwei Probleme:

  1. Wenn Sie Dispatcher.CurrentDispatcher aus dem Hintergrund-Thread verwenden, wird der Dispatcher-Hintergrund-Thread bekommen, nicht die Dispatcher-UI-Thread.

  2. Aus Ihrer Beschreibung entnehme ich, dass Ihre PartialEmployees.Clear() Methode erhebliche Zeit in Anspruch nimmt auszuführen, und Sie mögen während der Ausführung des UI-Thread vermeiden sperren. Allerdings wird eine Background invoke PartialEmployees.Clear() auf dem UI-Thread, die die gleiche Wirkung wie die DispatcherTimer verwenden, so dass Sie eine andere Lösung als die benötigen für Sie gehen.

Wenn Sie nur das Dispatcher.CurrentDispatcher Problem lösen wollen, speichern Sie nur die aktuelle Dispatcher in einer lokalen Variablen wie folgt aus:

private void dispTimer_Tick(object sender, EventArgs e) 
{
  var uiDispatcher = Dispatcher.CurrentDispatcher;

  BackgroundWorker _worker = new BackgroundWorker(); 
  _worker.DoWork += (sender, e) =>
    uiDispatcher.BeginInvoke(new Action(() =>
    {
      PartialEmployees.Clear();
    }));
  _worker.RunWorkerAsync(); 
} 

Dies wird dazu führen, dass UI Änderung zu arbeiten, aber es wird immer noch die Benutzeroberfläche während der Änderung einsperren, genau so, wie wenn Sie nicht Background benutzt hatten. Der Grund dafür ist:

  1. Das DispatcherTimer Feuer, auf dem UI-Thread ausgeführt wird. Alles, was es ist (dispTimer_Tick) ist ein Background und beenden Sie dann starten.
  2. Die Background führt auf eigenem therad. es tut, ist alles Zeitplan ein Rückruf Dispatcher und dann beenden.
  3. Die Dispatcher Rückruf läuft auf dem UI-Thread wieder. Er fordert PartialEmployees.Clear (), die eine Weile dauert, Ihre UI-Thread Perren, während sie ausgeführt wird.

So Ihr Verhalten ist das gleiche, als ob der DispatcherTimer Rückruf PartialEmployees.Clear genannt hatte () direkt. In jedem Fall ist die zeitaufwendige Operation auf dem UI-Thread ausgeführt wird,

Der Grund für die Überbrückungs ist, dass jedes Mal, wenn Sie auf der Benutzeroberfläche ein großes Stück Arbeit zu tun Faden erhalten Sie eine momentane Überbrückungs bekommen, während es läuft. Die Lösung ist Ihre Arbeit in kleinere Teile zu brechen und ihnen einen nach dem anderen, entweder von einem DispatcherTimer oder einem Background zu tun. In Ihrem Fall prüfen Sie den Code für PartialEmployees.Clear() zu sehen, ob es schrittweise durchgeführt werden kann.

Andere Tipps

Das Problem hierbei ist, dass Sie die Methode Dispatcher.CurrentDispatcher von der Rückseite Grundfaden verwenden. Was Sie brauchen, ist die Dispatcher-Instanz für den UI-Thread.

_worker.DoWork += delegate { DoWork(Dispatcher.CurrentDispatcher); };

...
private void DoWork(Dispatcher dispatcher) {
  dispatcher.BeginInvoke(new Action(() => {
    PartialEmployees.Clear();
  });
}

Ich denke nicht, daß Sie die Hintergrundarbeit benötigen, wie BeginInvoke auf dem Dispatcher läuft auf einem Threadpool-Thread.

so etwas wie dies funktionieren soll, und ist prägnanter

DispatcherTimer dispTimer = new DispatcherTimer 
    {Interval = TimeSpan.FromSeconds(45)};
dispTimer.Tick += (o,e) => Dispatcher.CurrentDispatcher
    .BeginInvoke((Action)PartialEmployees.Clear);
dispTimer.Start();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top