Farbanimation läuft nicht wie gewollt

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von kafffee.

    Farbanimation läuft nicht wie gewollt

    Hallo miteinander :)

    Ich habe einen farbanimierten SplashScreen mit diesem Code:

    VB.NET-Quellcode

    1. Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
    2. Dim FarbListe As New List(Of System.Windows.Media.Color)
    3. Dim rnd As New Random
    4. 'Dim MeineAnimation As New ColorAnimation
    5. For i = 0 To 9 'hier habe ich es mit mehr oder weniger Farben ausprobiert
    6. FarbListe.Add(System.Windows.Media.Color.FromRgb(rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255)))
    7. Next
    8. Dim animatedBrush As New SolidColorBrush()
    9. animatedBrush.Color = Color.FromArgb(255, 0, 0, 0)
    10. lblTitelLeiste.Background = animatedBrush
    11. Me.RegisterName("AnimatedBrush", animatedBrush)
    12. Dim colorAnimation As New ColorAnimationUsingKeyFrames()
    13. colorAnimation.Duration = TimeSpan.FromMilliseconds(10000) 'auch mit den Milllisekunden hab ich gespielt
    14. For Each Farbe In FarbListe
    15. colorAnimation.KeyFrames.Add(New LinearColorKeyFrame(Farbe)) ', KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(20)))) ' KeyTime - Target value (KeyValue) 'hier auch
    16. Next
    17. colorAnimation.RepeatBehavior = RepeatBehavior.Forever
    18. Storyboard.SetTargetName(colorAnimation, "AnimatedBrush")
    19. Storyboard.SetTargetProperty(colorAnimation, New PropertyPath(SolidColorBrush.ColorProperty))
    20. Dim myStoryboard As New Storyboard()
    21. myStoryboard.Children.Add(colorAnimation)
    22. myStoryboard.Begin(Me)
    23. End Sub


    Das funktioniert im Testprogramm ausgezeichnet, aber im Hauptprojekt zeigt es nach dem Laden nur die erste Farbe, und dann kurz bevor das Hauptprogramm geladen ist beim Schliessen zeigt es noch eine zweite Farbe.

    Ich nehme an, dass da einfach die UI nicht upgedatet wird, daher die Frage:

    Kann man die Methode vielleicht irgendwie in einem anderen Thread laufen lassen? Oder hat jemand sogar ne bessere Idee?

    Freu mich auf Eure Antworten :)

    kafffee
    Ich glaube ich habe schon mal gesagt, das deine Code-Architektur nicht gut ist. Nun willst du das noch verschlimmern und UI Sachen mit MT verquirlen. Wenn dein UI nicht hinterherkommt weil der Thread irgendwo blockiert ist wäre es evtl. besser diese dicken Aufgaben die den UI Thread blockieren parallel zu machen.

    Ich benutze in meinem Mediaplayer auch MT, aber nur bei Sachen die den UI Thread zum einfrieren bringen können. Also beim Verbinden zu einem Webbradio mit der BASS, oder zum Downloaden/Uploaden von Daten bei radio-browser.info. Dazu noch zum Im- und Ex-portieren von Daten. Mehr MT(oder Async) braucht es doch nicht.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    DTF schrieb:

    Nun willst du das noch verschlimmern und UI Sachen mit MT verquirlen.


    Von wollen kann keine Rede sein, aber ich kann mir nicht anders helfen...

    DTF schrieb:

    wäre es evtl. besser diese dicken Aufgaben die den UI Thread blockieren parallel zu machen.


    Okay das wäre ja dann einfach nur der Aufruf in Zeile 9 und 10. Wie schlägst du vor mach ich das parallel? So in etwa?:

    VB.NET-Quellcode

    1. Dim StarteMainWindowThread As New Thread(AddressOf MainWindow_Start)
    2. StarteMainWindowThread.IsBackground = True
    3. StarteMainWindowThread.Start()
    4. Private Sub MainWindow_Start
    5. ViewModel.Services.ServiceContainer.Instance.AddService(Of ViewModel.Services.IMainWindowService)(New Services.MainWindowService)ViewModel.Services.ServiceContainer.GetService(Of ViewModel.Services.IMainWindowService).OpenWindow(1000, 500, "Hauptfenster", Nothing, Me)
    6. End Sub


    Bisher hab ich es so:

    VB.NET-Quellcode

    1. Private Sub Application_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
    2. ...
    3. Dim windowService = ServiceContainer.GetService(Of IWindowService)
    4. Dim SplashScreenVM As New ViewModel.SplashScreen
    5. MainModule.SplashScreenInstanz = SplashScreenVM
    6. MainModule.SplashScreenInstanz.Meldung = "Programm wird gestartet..."
    7. windowService.OeffneSplashScreen(500, 500, "", SplashScreenVM, Me, False, False, ViewModel.Services.WindowStyle.None, ViewModel.Services.ResizeMode.NoResize, ViewModel.Services.SizeToContent.WidthAndHeight, ViewModel.Services.WindowStartupLocation.CenterScreen, "Es geht gleich weiter...")
    8. ViewModel.Services.ServiceContainer.Instance.AddService(Of ViewModel.Services.IMainWindowService)(New Services.MainWindowService)
    9. ViewModel.Services.ServiceContainer.GetService(Of ViewModel.Services.IMainWindowService).OpenWindow(1000, 500, "Hauptfenster", Nothing, Me)
    10. windowService.CloseSplashScreen()
    11. ...
    12. End Sub
    Du fängst schon ganz falsch an. Warum die Fenster nebenläufig erzeugen? Fenster ganz normal im UI Thread erzeugen, wenn du was in diesem Thread ausführst was den Thread blockiert, das(und nur das!) lagerst du dann in einem Thread aus oder nutzt Async.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    Okay klingt interessant :)

    Aber hab dazu zwei Fragen:

    DTF schrieb:

    Fenster ganz normal im UI Thread erzeugen,


    Wo meinst du genau? Du weisst es ist ne MVVM App?

    DTF schrieb:

    das lagerst du dann aus

    Wie genau? So wie ich geschrieben hab das mit dem MainWindowThread?

    Ich komm an deine Skills noch nicht ran, also nehms mir nicht übel :)
    Ach, übel nehm ich dir das nicht. Aber höre auf meinen Rat, ich habe dir schonmal gesagt, du hast dich verrant. Du hast vermutlich auch kaum noch überblick was/wo/warum in welchen Thread abgeht. Plane anständig neu, notiere was nebenläufig sein muss, das und nur das machst du dann nebenläufig. Ist ja nicht so das du den ganzen Code neu schreiben musst, so einiges wrist du kopieren können.

    So einfach kann es sein, arbeiten auszuführen ohne den UI-Thread zu blockieren. Du kannst aber auch Async nutzen, anstatt von Threads.

    PS.
    @kafffee
    Ja, ich weiss, das du MVVM nutzt. Das Beispiel ist zwar Forms, in WPF brauchst du dann den Dispatcher vom Window. Aber du kannst auch Async nutzen um das zu vermeiden. Dann aber nur das Async ausführen was sein muss.

    VB.NET-Quellcode

    1. namespace WinFormsApp1
    2. {
    3. public partial class Form1 : Form
    4. {
    5. public Form1()
    6. {
    7. InitializeComponent();
    8. }
    9. class MyResult
    10. {
    11. public MyResult(string message)
    12. {
    13. this.Message = message;
    14. }
    15. public string Message { get; }
    16. }
    17. public void StartThreadWork()
    18. {
    19. Thread t = new Thread(ThreadWork);
    20. t.Start();
    21. Text = "Threadwork started...";
    22. }
    23. private void ThreadWork()
    24. {
    25. //z.B. Dateisuche oder andere Sachen die den Thread blockieren.
    26. Thread.Sleep(2500);
    27. MyResult result = new MyResult("Threadwork done!");
    28. BeginInvoke(() => OnThreadWorkDone(result));
    29. //oder auch
    30. //Invoke(() => OnThreadWorkDone(result));
    31. }
    32. private void OnThreadWorkDone(MyResult result)
    33. {
    34. Text = result.Message;
    35. }
    36. private void Form1_Load(object sender, EventArgs e)
    37. {
    38. StartThreadWork();
    39. }
    40. }
    41. }

    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „DTF“ ()

    DTF schrieb:

    Aber du kannst auch Async nutzen um das zu vermeiden. Dann aber nur das Async ausführen was sein muss.


    Hab jetzt das hier. Das Problem bleibt bestehen, aber was bemerkenswert ist, wenn ich die MessageBox anzeige, dann funktioniert die Animation, bis ich dann natürlich auf OK klicke... dann wird der SplashScreen geschlossen. Startvorgang_Execute() wird ausgeführt beim MainWindow_Loaded-Event.

    VB.NET-Quellcode

    1. Private Async Sub Startvorgang_Execute(obj As Object)
    2. 'MessageBox.Show("Angehalten!")
    3. Await Initialize()
    4. End Sub
    5. Private Async Function Initialize() As Task
    6. Dim MeineRegistrierung As New Registrierung
    7. Await MeineRegistrierung.Start
    8. If MainModule.AccessGranted Then
    9. MainModule.LayerVM.SucheViewModel.Initialisieren()
    10. End If
    11. End Function

    kafffee schrieb:

    dann funktioniert die Animation, bis ich dann natürlich auf OK klicke... dann wird der SplashScreen geschlossen.


    Weil du da ein modales Fenster hat, worauf der Rest deine Applikation warten muss
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems

    Selbstständiger Softwareentwickler & IT-Techniker.