| 

.NET C# Java Javascript Exception

3
Moin,
ich habe jetzt verschiedene Varianten probiert (Thread.Start, Threadpool.QueueUserWorkItem, Task<T>.Factory...) und irgendwie wird die GUI erst NACH abarbeiten der Aufgabe aktualisiert, und das ist irgendwie ganz schlecht für die Fortschrittsanzeige...
Es gibt eine Methode Transmit(), die durch Benutzeraktuiion angestoßen wird. Da die Operation etwas dauern kann, wird in Transmit() ein Task gestartet, der die eigentliche Arbeit erledigt: TransmitAsync. Letztere Methode aktualisiert ein Property UploadProgress, an welches der Value der Progressbar der GUI gebunden ist. Value der Progressbar wird auch aktualisiert, allerdings erst, wenn der Task abgearbeitet ist und nicht während der Task arbeitet. Bin ratlos. Hier die Methoden, TransmitAsync ist nur ein Dummy:
private void Transmit() {
this.IsTransmitting = true;
Task<string> task = Task<string>.Factory.StartNew(() => TransmitAsync());
task.Wait();
string msg = task.Result;
this.RequestDisplayDialog(new RequestDialogEventArgs(msg,MessageStates.Info));
}

private string TransmitAsync() {
this.IsTransmitting = true;
this.UploadProgress = 10;
string msg = "";
int s = DateTime.Now.Second;
int t = s + 5;
while (s < t) {
s = DateTime.Now.Second;
double d = 0d;
if (DateTime.Now.Millisecond % 500 == 0) {
d = d + 10;
ThreadPool.QueueUserWorkItem(_ => { this.UploadProgress = d; });
//this.UploadProgress = d;
}
}

<ProgressBar Height="10"
Value="{Binding UploadProgress,UpdateSourceTrigger=PropertyChanged}"
DockPanel.Dock="Left"
HorizontalAlignment="Stretch" />

Grüße
Christian
05.09.2011
chriscolm 126 1 3
3 Antworten
4
Hallo chriscolm,

in der Methode Transmit() liegt das Problem. Wenn diese Methode vom UI Thread aufgerufen wird und Du diesen nach dem Starten des Tasks mit einem
task.Wait();

auf den Abschluss der Aufgabe warten lässt (blockierend), kann er den Frostschritt(EDIT: Ähem: ich meinte Fortschritt) nicht aktualisieren.
Wenn Du nicht auf event-based Async-Pattern umstellen willst (wird z.B. vom BackgroundWorker implementiert), dann kannst Du es mit einem Busy-Wait ala DoEvents() versuchen. Hier findest Du ein Application.DoEvents für WPF. Sieht so aus:
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));


Wenn Du das ganze jetzt in einer BusyWait-Schleife implementierst, sieht deine Transmit Methode so aus:

private void Transmit() {
this.IsTransmitting = true;
Task<string> task = Task<string>.Factory.StartNew(() => TransmitAsync());
while(!task.Wait(100))
{
// pump messages
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
}
string msg = task.Result;
this.RequestDisplayDialog(new RequestDialogEventArgs(msg,MessageStates.Info));
}


Das sollte klappen. Allerdings wäre wirklich zu überlegen, ob Du nicht eine andere Lösung finden kannst (z.B. ohne Warten, nur Callbacks), die auf den BusyWait verzichten kann.

Viele Erfolg
Florian
05.09.2011
ffordermaier 8,4k 3 9
1
Hi,

hier wurde das mit dem Backgroundworker behandelt. Hat bei mir super geklappt.
Codekicker
05.09.2011
mrmee 745 1 8
mrmee 745 1 8
1
mit dem Backgroundworker klappt das auch, man könnte auch direkt Threads verwenden. Aber in WPF hat man mit den neuen Tasks (seit .Net 4) noch einige Vorteile und es ist noch einfacher zu verwenden und synchronisieren.
Deshalb würde ich in WPF schon eher beim Task bleiben
michlG 05.09.2011
1
Hi,
danke erstmal, das mit dem Task.Wait war der Knackpunkt. Task.Wait und Task.Result rausgeschmissen, und das Benachrichtigungsevent wird im Task ausgelöst nach getaner Arbeit und es funzt.
Grüße
Christian
05.09.2011
chriscolm 126 1 3

Stelle deine Gui-Frage jetzt!