mikrocontroller.net

Forum: PC-Programmierung wpf bilder im anderen Task faden


Autor: Lisa (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich habe eine xaml mit einem Storyboard mit welchen ich Bilder 
einfadenlassen kann
<Storyboard x:Key="FadeIn" >
<DoubleAnimation Duration="0:0:.25" Storyboard.TargetProperty="Opacity" From="0" To="1" />
</Storyboard>

wenn ich jetzt das Storyboard auch meinem Bild anwende
Storyboard StFadeOut = Resources["FadeOut"] as Storyboard).Clone();
StFadeOut.Begin(bild);

dann erscheint das "langsam" ...

nun möchte ich aber in einem anderen Task das ganze anwenden aber leider 
kann ich das Storyboard irgendwie nicht freigeben:
Beitrag "WPF C# image.Source wieder freigeben"
diese News habe ich gesehen, und nach dieser News müsste ich ja nur
das Storybord im Hauptthread Freezen und im Task dispatchen... leider 
klappt das nicht

Storyboard StFadeOut;
Main() {

StFadeOut = Resources["FadeOut"] as Storyboard).Clone();
StFadeOut.freeze();
}


Task() {
  StFadeOut.Dispatcher.Invoke(new Action(() =>
  {
    StFadeOut.Begin(bild);
  }));
}


leider funktioniert das "gar nicht"

vielen Dank für Tipp

* drück *
Lisa

Autor: Frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lisa schrieb:
> leider funktioniert das "gar nicht"

Was heißt den gar nicht?

Folgendes fällt mir auf:

1. Im XAML hat dein Storyboard den Key "FadeIn", im C#-Code greifst du 
aber auf ein Storyboard "FadeOut" zu.
2. Warum klonst du das Storyboard?
3. Warum der Aufruf von Freeze?

Der folgende Code funktioniert bei mir jedenfalls problemlos:
<Storyboard x:Key="FadeIn" >
  <DoubleAnimation Duration="0:0:.25" Storyboard.TargetProperty="Opacity" From="0" To="1" />
</Storyboard>
var StFadeIn = (Storyboard)Resources["FadeIn"];
var t = new Task(() =>
{
  StFadeIn.Dispatcher.Invoke(new Action(() =>
  {
    StFadeIn.Begin(bild);
  }));
});

t.Start();

Autor: Lisa (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Okay, vielen dank...

das funktioniert jetzt so...

allerdings habe ich noch immer etwas was ich mir "anders" vorgestellt 
habe...

mein Aufbau:
Storyboard StFadeOut;
main() {
StFadeIn = (Storyboard)Resources["FadeIn"];
FadeImage();
}

public async Task FadeImage()
{
  await Task.Run(() =>
  {
    StFadeIn.Dispatcher.Invoke(new Action(() =>
    {
      Thread.Sleep(5000);
      StFadeIn.Begin(bild);
    }));
  });
}

während der 5 Sekunden, dreht sich meine Sanduhr und auch die App 
"hängt" ... somit läuft das nicht in einem Hintergrund-Task sondern 
belegt die App ...

was ist der Unterschied zwischen

> var t = new Task(() =>
> t.Start();
UND
> await Task.Run(() =>

=> Wobei auch hier genau das selbe Ergebnis herauskommt... vermutlich 
nur eine andere "Schreibweise"???

Ziel ist es Bilder Ein- oder Auszufaden, und das selbstverständlich so, 
dass die App nicht belegt ist <- klar kommen die 5Sekunden schlafen noch 
weg und das ganze wird über einen "DispatcherTimer" aufgerufen... aber 
ich will auch nicht, dass die App hängt, wenn ich 2 Sekunden fade oder 
so (daher kann mann das Sleep sinnbildlich als Reservator für den 
Hintergrundprozess sehen)...

> evtl. ist auch meine Herangehensweise überarbeitbar, dann bin ich offen für 
Kritik :)

* drück *
Lisa

Autor: Frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Aufruf von
Dispatcher.Invoke(...)
 dient ja dazu, den angegebenen Code (in deinem Fall das Starten des 
Storyboards) im GUI-Thread auszuführen. D.h. auch dein
Thread.Sleep(5000)
 wird im GUI-Thread ausgeführt, was diesen dann blockiert.

Für gewöhnlich führt man alle lang andauernden Operationen (in deinem 
Fall vermutlich das Laden eines Bildes aus irgendeiner Quelle) in einem 
Hintergrundthread durch. Wenn die Daten dann vollständig geladen sind, 
aktualisiert man die GUI. Das entspricht ja schon mal deinem Vorgehen, 
das passt also soweit.
Natürlich muss man darauf achten, dass man die Operationen, die im 
GUI-Thread laufen, so kurz wie möglich hält.

Im Code ausgedrückt:
public async Task FadeImage()
{
  await Task.Run(() =>
  {
    // Zeitintensive Operationen hier ausführen
    Thread.Sleep(5000);

    StFadeIn.Dispatcher.Invoke(new Action(() =>
    {
      // Hier nur noch die GUI aktualisieren
      StFadeIn.Begin(bild);
    }));
  });
}

Lisa schrieb:
> aber
> ich will auch nicht, dass die App hängt, wenn ich 2 Sekunden fade oder
> so

In diesem konkreten Beispiel gilt: WPF kümmert sich schon darum, dass 
die Anwendung während des Fadens weiterhin reagiert (probiers einfach 
mal aus, indem du Zeit im Storyboard erhöhst).

Ohne jetzt zu tief ins Detail gehen zu wollen: Man kann das erreichen 
indem man die lang andauernde Operation immer wieder kurz "unterbricht" 
und die MessageQueue abarbeitet. Aus persönlicher Erfahrung rate ich dir 
die Finger davon zu lassen. So etwas sorgt in regelmäßigen Abständen für 
die kuriosesten Bugs (muss beruflich selbst eine Anwendung betreuen, in 
der so etwas gemacht wird ;-)).

Daher gilt (wie oben schon geschrieben): Lang dauernde Operationen im 
Hintergrundthread durchführen und dann nur noch die GUI aktualisieren.

Lisa schrieb:
> was ist der Unterschied zwischen
>
>> var t = new Task(() =>
>> t.Start();
> UND
>> await Task.Run(() =>
>
> => Wobei auch hier genau das selbe Ergebnis herauskommt... vermutlich
> nur eine andere "Schreibweise"???
await Task.Run(() =>

Zum einen startet das den Task und entspricht damit dem ersten Code. Das 
await (was übrigens nur in Methoden verwendet werden kann, die als async 
gekennzeichnet sind), wartet aber auch bis der Task abgeschlossen ist. 
Das heißt, Code der nach dem mit await gekennzeichneten Aufruf kommt, 
wird erst ausgeführt, wenn der Task abgearbeitet ist:
private async void Test()
{
  await Task.Run(() => Thread.Sleep(5000));

  MessageBox.Show("Diese MessageBox wird erst nach 5 Sekunden angezeigt.");
}

Während das async auf die Beendigung des Tasks wartet, wird die 
Kontrolle übrigens an den Aufrufer der asynchronen Methode 
zurückgegeben:
private void MyMethod()
{
  Test();

  MessageBox.Show("Diese MessageBox wird sofort angezeigt.");
}

private async void Test()
{
  await Task.Run(() => Thread.Sleep(5000));

  MessageBox.Show("Diese MessageBox wird erst nach 5 Sekunden angezeigt.");
}

Autor: Frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry gerade fällt mir noch auf:

Frank schrieb:
> public async Task FadeImage()
> {
>   await Task.Run(() =>
>   {
>     // Zeitintensive Operationen hier ausführen
>     Thread.Sleep(5000);
>
>     StFadeIn.Dispatcher.Invoke(new Action(() =>
>     {
>       // Hier nur noch die GUI aktualisieren
>       StFadeIn.Begin(bild);
>     }));
>   });
> }

hier sollte man das await natürlich weglassen. Sonst blockiert der 
Aufruf von FadeImage() wirklich so lange, bis die lang andauernden 
Operationen abgeschlossen sind.

Autor: Lisa (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
dankeschön <3 ...

sehr sehr gut

lg lisa

Autor: Lisa (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
evtl. noch eine Frage.

Kann ich irgendwo testen welches Storyboard angewandt wurde?

also wenn ich jetzt 2 Storyboards habe:
FadeOut.Begin(Bild)

==> TESTE FadeOut an Bild => TRUE

FadeIn.Begin(Bild)

==> TESTE FadeOut an Bild => FALSE

Danke =)
lisa

Autor: Lisa (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
okay, überflüssige frage...
> nicht das Storyboard ist interessant sondern die Opacity, und die kann ich 
leicht erfragen...

hihi ... danke

Autor: Lisa (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

wie kann ich die "Duration" mit C#-Code ändern?
<Storyboard x:Name="FadeOut" x:Key="FadeOut">
<DoubleAnimation Duration="0:0:0.5" Storyboard.TargetProperty="Opacity" AccelerationRatio="0.4" DecelerationRatio="0.4" From="1" To="0" />
</Storyboard>

FadeOut.DoubleAnimation.Duration = "0:0:5" <- ist zu einfach gedacht ^^

lisa

Autor: Lisa (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hier hab ich auch die Lösung gefunden...

Für euch:
DoubleAnimation dFOut = (DoubleAnimation)StFadeOut.Children[0];
dFOut.Duration = new Duration(new TimeSpan(ts));

lisa

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.