Fortschritt-bar nicht immer aktualisiert auf WPF-Benutzeroberfläche
Ich verwende folgenden code um den Fortschritt anzuzeigen status bar in WPF (MVVM) - app, die im Grunde auf einen thread, aber wenn ich sage, die auf einem dispatcher-thread-status nicht aktualisiert UI.
Mit Gewinde:
Main()
{
Thread LoadApp = new Thread(MyData);
LoadApp.Start();
}
public void MyData()
{
ProgMessage = "10%";
ProgValue = 10;
var varAction = new List<Func<object>>();
varAction .Add(() => (MainViewMode1)ViewModel1.ViewModel1);
varAction .Add(() => (MainViewMode2)ViewModel2.ViewModel2);
varAction .Add(() => (MainViewMode3)ViewModel3.ViewModel3);
foreach (var action in varAction )
{
var obj = action();
ProgressMessage = //My message from VM
ProgressBarValue += //My message valuefrom VM;
}
}
Dies ist in Ordnung, aber da jetzt bin ich mit Abhängigkeitseigenschaft ich habe das cross-threading Ausnahme (STA), also änderte ich den code, um:
Main()
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
{
MyData();
}));
}
public void MyData()
{
ProgMessage = "10%";
ProgValue = 10;
var varAction = new List<Func<object>>();
varAction .Add(() => (MainViewMode1)ViewModel1.ViewModel1);
varAction .Add(() => (MainViewMode2)ViewModel2.ViewModel2);
varAction .Add(() => (MainViewMode3)ViewModel3.ViewModel3);
foreach (var action in varAction )
{
var obj = action();
ProgressMessage = //My message from VM
ProgressBarValue += //My message valuefrom VM;
}
}
Ich jetzt loswerden threading-Fehler, aber nicht die Aktualisierung der Statusanzeige-status auf UI ?
Jeder Hinweis auf diese ?
- Haben Sie mit dem data-binding? Wenn es so ist, dann müssen Sie einige XAML-Code zeigt, wie binden Sie die ProgressBar-Komponente viewmodel
- Ja. Ich bin mit der Datenbindung.Der Xaml-code: <dxe:ProgressBarEdit Name="ProgressBar" Minimum="0" Maximum="100" ContentDisplayMode="Wert" DisplayFormatString="{}{0}%" Value="{Binding ProgressBarValue}" > </dxe:ProgressBarEdit> <TextBlock Text="{Binding ProgressMessage}" />
- Setzen Sie einen Haltepunkt in der foreach-Schleife und sehen, ob die Werte updateing in diesen beiden Eigenschaften . Wenn Sie sind, dann stellen Sie sicher, dass Sie benachrichtigt werden die änderungen und Ihre Bindung korrekt ist
- Ja, diese Eigenschaften sind immer aktualisiert, aber seit ich ihn auf disptacher Sie sind nicht reflektiert wird in der Benutzeroberfläche . Bcoz gleiche Arbeit im Fall des Durchzugs.
- Haben Sie sich auf die Progressbar.ReportsProgress?
Du musst angemeldet sein, um einen Kommentar abzugeben.
UI-Elemente wird nicht aktualisiert, bis Sie die Kontrolle aufzugeben der dispatcher-thread. Normalerweise würden Sie hierzu wieder in die event-Schleife, was in der Regel bedeutet nur die Rückkehr. Aber wenn Sie haben eine Last von Arbeit zu tun in einer Schleife, dann ist das nicht wirklich praktisch. So im Allgemeinen, die Sie nicht wollen, um diese Art von Arbeit auf dem UI-thread.
Wenn Sie sagen, Sie "Verwendung von dependency property" meinst du, dass dein ViewModel-Klasse, die Eigenschaften sind abhängigkeitseigenschaften? Möchten Sie vielleicht zu überdenken, dass, weil es verhindert, dass multi-threaded verwenden. Wenn Sie machen den normalen, nicht-auto-Eigenschaften, können Sie immer noch verwenden Sie Datenbindung, um Sie zu verbinden, um die UI. Um die Benutzeroberfläche zu aktualisieren, wenn Sie die Eigenschaften ändern, müssen Sie implementieren
INotifyPropertyChanged
, und Sie machen Ihre Eigenschaften erhöhen die Benachrichtigungen ändern, dann werden Sie feststellen, dass Sie in der Lage sind zu arbeiten, die auf einem "worker thread" wie in deinem ersten Beispiel, und wenn Sie binden die Eigenschaften der UI wirst du nicht bekommen threading Ausnahmen, und es werde zu aktualisieren, einfach nur gut.(WPF data binding system erkennt, wenn eine gebundene Eigenschaft ändert, auf einem anderen thread als dem UI-thread und automatisch ordnet für die Aktualisierung der Benutzeroberfläche von richtigen thread. Aber Sie können nicht verwenden Sie den DPs in Ihrem VM-wenn Sie möchten, dies zu nutzen, weil DPS haben, die thread-Affinität.)
Den
DoEvents
Stil Ansatz, jemand anderem vorgeschlagen wird, wird funktionieren, aber es ist problematisch, und ich vermeide es. Es ermöglicht die re-entrancy - wenn der Benutzer mit der app interagiert in einer Weise, die bewirkt, dass die Ereignisprozeduren zu laufen, Sie laufen im inneren rufen, umDispatcher.PushFrame
. Dies ist nicht unbedingt ein problem, aber es ist sehr leicht zu bekommen in ein Chaos.Doch ein anderer Ansatz wäre, um die Arbeit zu tun auf der worker-thread, aber
Dispatcher.Invoke
eine Methode aufrufen, die updates derProgressMessage
undProgressBarValue
Eigenschaften. So, Ihre Arbeit erfolgt auf einem worker-thread (aus dem UI-thread frei, um zu aktualisieren), aber Sie werden aktualisieren DPs auf dem UI-thread, der vermeidet die Fehler.