.
Anmeldung | Registrieren | Hilfe
in Suchen

BusyIndicator

Letzter Beitrag 07. Apr 2015 11:47 von Anonymous. 12 Antworten.
Seite 1 von 1 (13 Treffer)
Beiträge sortieren: Zurück Weiter
  • 30. Mrz 2015 11:50

    • kermitfrosch
    • Top 200 Mitwirkender
    • Registriert am 30. Mrz 2015
    • Beiträge 7
    • Punkte 125

    BusyIndicator

    Hallo NG,

    ich habe folgendes Problem:

    WPF Anwendung mit MVVMLight (https://mvvmlight.codeplex.com/)
    MainWindow mit BusyIndicator (http://wpftoolkit.codeplex.com/wikipage?title=BusyIndicator)
    In meiner MainView (CodeBehind) wähle ich einen Kunden und versende eine Nachricht mit eben diesem Kunden:

    var debitor = _dataService.LoadDebitor(view.SelectedKunde.DEB_MAND, view.SelectedKunde.DEB_KONTONR);
    Messenger.Default.Send(new DebitorChangeMessage {SelectedDebitor = debitor});


    In verschiedenen Bereichen der MainView habe ich UserControls mit zugehörigem ViewModel. Jedes UC registriert sich
    für diese Nachricht und lädt dann die Benötigten Daten.
    Vor dem Laden der Daten sendet jedes UC(bzw. das VM) wiederum eine Nachricht.

     private void DebitorChangedReceiveMessage(DebitorChangeMessage msg)
            {
                try
                {
                    Messenger.Default.Send(new RegisterToWorkMessage { ViewModelName = ViewModelName });
    
                    var watch = Stopwatch.StartNew();
                    _logger.DebugFormat("Lade Daten für ViewModel: {0}", ViewModelName);
                    var _worker = new BackgroundWorker { WorkerSupportsCancellation = true };
                    _worker.DoWork += (sender, e) => DispatcherHelper.UIDispatcher.InvokeAsync(() =>
                    {
                        // Daten laden
                        
                        
                    });
                    _worker.RunWorkerCompleted += (sender, e) => DispatcherHelper.UIDispatcher.InvokeAsync(() =>
                    {
                        _logger.DebugFormat("Das laden der Viewmodels: {0} dauerte: {1}", ViewModelName, watch.Elapsed);
                        Messenger.Default.Send(new UnRegisterToWorkMessage {ViewModelName = ViewModelName});
                    });
                    _worker.RunWorkerAsync();
                }
                catch (Exception ex)
                {
                    Messenger.Default.Send(new UnRegisterToWorkMessage {ViewModelName = ViewModelName});
                    _logger.Error(ex);
                    throw;
                }
            }


    In meinem MainViewModel möchte ich jetzt meine Application in den BusyZustand versetzen:

    private void RegisterToWork(RegisterToWorkMessage vm)
            {
                if (!_busyCollection.Contains(vm.ViewModelName))
                    _busyCollection.Add(vm.ViewModelName);
            }
    
            private void UnRegisterToWorkMessage(UnRegisterToWorkMessage vm)
            {
                if (_busyCollection.Contains(vm.ViewModelName))
                    _busyCollection.Remove(vm.ViewModelName);
            }
    
            private void BusyCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                IsApplicationBusy = _busyCollection.Count > 0;
                _logger.DebugFormat("IsBusy: {0}", IsApplicationBusy);
            }


    Soweit funtioniert alles und es werden auch alle Events in der richtigen Reihenfolge aufgerufen, nur wird eben der BusyIndicator nicht
    angezeigt. Ein Problem mit der Datenbindung kann ich ausschliessen, das wenn ich hardcoded IsBusy=true setze wird der Indicator richtig angezeigt.

    Ich hoffe ich hab mich verständlich ausgedrückt.

    Gruss
    Jens
    Abgelegt unter: , , ,
    • IP-Adresse ist Registriert
  • 30. Mrz 2015 14:36 Antwort zu

    • MitchMurder
    • Top 100 Mitwirkender
    • Registriert am 04. Dez 2014
    • Berlin
    • Beiträge 16
    • Punkte 245

    BusyIndicator

    Bitte formatiere den Eintrag mal entsprechend den Vorgaben. Externe Links sollte man anklicken können, Code sollte auch als solcher dargestellt werden (Code-Tags).

    In der jetztigen Form mag das niemand lesen geschweige denn sich den Code näher ansehen. ;-)

    EDIT:
    Wird denn die Methode
    BusyCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    überhaupt ausgeführt, also erscheint der Debug printout? Wenn nicht, würde ich einen Breakpoint setzen und step-by-step mal durch den Code nach dem Senden-Aufruf gehen.
    • IP-Adresse ist Registriert
  • 30. Mrz 2015 15:21 Antwort zu

    • kermitfrosch
    • Top 200 Mitwirkender
    • Registriert am 30. Mrz 2015
    • Beiträge 7
    • Punkte 125

    BusyIndicator

    Hallo, danke für den Hinweis, aber ich habe unter IE11 keine Symbolleiste um Code einzufügen bszw. Links einzufügen.
    Mit Chrome hab ich eine Symbolleiste, aber die Formatierung ist auch Schrott.
    Jetzt Firefox installiert.

    Die CollectionChanged Methode wird korrekt ausgeführt. 
    Jens
    • IP-Adresse ist Registriert
  • 30. Mrz 2015 21:51 Antwort zu

    • MitchMurder
    • Top 100 Mitwirkender
    • Registriert am 04. Dez 2014
    • Berlin
    • Beiträge 16
    • Punkte 245

    BusyIndicator

    Wenn du IsApplicationBusy manuell setzen kannst und die Bindung funktioniert, dann wird dieser Vergleich:
    IsApplicationBusy = _busyCollection.Count > 0;
    eventuell nie wahr.

    _logger.DebugFormat("IsBusy: {0}", IsApplicationBusy);
    Was wird hier ausgegeben? true oder false?
    • IP-Adresse ist Registriert
  • 31. Mrz 2015 7:59 Antwort zu

    • kermitfrosch
    • Top 200 Mitwirkender
    • Registriert am 30. Mrz 2015
    • Beiträge 7
    • Punkte 125

    BusyIndicator

    IsBusy wird im ViewModel korrekt gesetzt. Screenshot anbei
    • IP-Adresse ist Registriert
  • 31. Mrz 2015 9:22 Antwort zu

    • MitchMurder
    • Top 100 Mitwirkender
    • Registriert am 04. Dez 2014
    • Berlin
    • Beiträge 16
    • Punkte 245

    BusyIndicator

    Ok, der Screenshot zeigt aber auch, dass alles in ein und derselben Sekunde ausgegeben wird.
    Und zwar exakt um:  07:57:09

    Ist das der ganze Log? Wenn ja ist die Dauer eventuell einfach zu kurz, um das Update der UI wahrzunehmen. Ich würde hier zum klassischen Ausschlussverfahren raten. Du kannst den Backgroundworker ja nach Beendigung seiner Aufgabe mal für 1-2 Sekunden "schlafen legen". Wenn der BusyIndicator dann nicht angezeigt wird, kannst du zumindest meine These mit der Zeit verwerfen.

    Könntest du eventuell auch ein kleines lauffähiges Programm zur Verfügung stellen, welches das Problem reproduziert?
    • IP-Adresse ist Registriert
  • 31. Mrz 2015 9:28 Antwort zu

    • kermitfrosch
    • Top 200 Mitwirkender
    • Registriert am 30. Mrz 2015
    • Beiträge 7
    • Punkte 125

    BusyIndicator

    Werd ich testen.
    Hier mein Sample
    • IP-Adresse ist Registriert
  • 31. Mrz 2015 10:20 Antwort zu

    • kermitfrosch
    • Top 200 Mitwirkender
    • Registriert am 30. Mrz 2015
    • Beiträge 7
    • Punkte 125

    BusyIndicator

    Ich habe mal in eine Datei geloggt:
    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    2015-03-31 10:16:09,117 Music DEBUG Ag.KundenInfo.ViewModel.DetailViewModel [(null)] - DetailViewModel created.
    2015-03-31 10:16:11,383 Music DEBUG Ag.KundenInfo.ViewModel.AuswahlenViewModel [(null)] - AuswahlenViewModel created.
    2015-03-31 10:16:18,558 Music DEBUG Ag.KundenInfo.ViewModel.MainViewModel [(null)] - IsBusy: True
    2015-03-31 10:16:18,559 Music DEBUG Ag.KundenInfo.ViewModel.MainViewModel [(null)] - IsBusy: True
    2015-03-31 10:16:18,561 Music DEBUG Ag.KundenInfo.ViewModel.MainViewModel [(null)] - IsBusy: True
    2015-03-31 10:16:18,561 Music DEBUG Ag.KundenInfo.ViewModel.UmsatzViewModel [(null)] - Lade Daten für ViewModel: UmsatzViewModel
    2015-03-31 10:16:18,562 Music DEBUG Ag.KundenInfo.ViewModel.MainViewModel [(null)] - IsBusy: True
    2015-03-31 10:16:18,563 Music DEBUG Ag.KundenInfo.ViewModel.ReiseberichtViewModel [(null)] - Lade Daten für ViewModel: ReiseberichtViewModel
    2015-03-31 10:16:18,584 Music DEBUG Ag.KundenInfo.ViewModel.MainViewModel [(null)] - IsBusy: True
    2015-03-31 10:16:25,483 Music INFO  Ag.KundenInfo.ViewModel.ReiseberichtViewModel [(null)] - Dauer für das laden der ReiseberichtsDetails: 00:00:00.59
    2015-03-31 10:16:25,805 Music DEBUG Ag.KundenInfo.ViewModel.MainViewModel [(null)] - IsBusy: True
    2015-03-31 10:16:25,806 Music DEBUG Ag.KundenInfo.ViewModel.MainViewModel [(null)] - IsBusy: True
    2015-03-31 10:16:25,807 Music DEBUG Ag.KundenInfo.ViewModel.UmsatzViewModel [(null)] - Das laden der Viewmodels: UmsatzViewModel dauerte: 00:00:07.2441335
    2015-03-31 10:16:25,808 Music DEBUG Ag.KundenInfo.ViewModel.MainViewModel [(null)] - IsBusy: True
    2015-03-31 10:16:25,808 Music DEBUG Ag.KundenInfo.ViewModel.ReiseberichtViewModel [(null)] - Das laden der Viewmodels: ReiseberichtViewModel dauerte: 00:00:07.2436823
    2015-03-31 10:16:25,809 Music DEBUG Ag.KundenInfo.ViewModel.MainViewModel [(null)] - IsBusy: True
    2015-03-31 10:16:25,816 Music DEBUG Ag.KundenInfo.ViewModel.MainViewModel [(null)] - IsBusy: False
    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Jetzt sehen die Zeiten besser aus. Ist wohl ein Problem von meinem Tool (https://log2console.codeplex.com/)
    • IP-Adresse ist Registriert
  • 31. Mrz 2015 12:21 Antwort zu

    • MitchMurder
    • Top 100 Mitwirkender
    • Registriert am 04. Dez 2014
    • Berlin
    • Beiträge 16
    • Punkte 245

    BusyIndicator

    Ok, ich hab mir dein Sample angesehen.

    Was auffällt ist, dass das UI komplett einfriert, sobald man den Button klickt.
    Das ist darauf zurück zu führen, dass dein Backgroundworker den MainThread in der for-Schleife für jeweils 50ms warten lässt. Das macht natürlich keinen Sinn. ;-)

    Das Problem hier ist also folgendes: Du klickst den Button, IsBusy wird dann True, der MainThread kann aber das UI nicht updaten, da er beschäftigt ist. Nachdem die Aufgabe beendet ist, wird das UI aktualisiert, allerdings ist IsBusy dann schon wieder False, da die List _busyCollection bereits leer ist.

    Dein Tool hat also gar keine Chance, den BusyIndicator anzuzeigen. Prüfen kannst du das, in dem du mal folgendes machst:
    Ersetze Line:55 in MainViewModel.cs :
    IsBusy = _busyCollection.Count > 0;
    durch:
    IsBusy = true;

    Dann bleibt IsBusy nach Beendigung der Aufgabe auf True und sobald der MainThread frei ist, wird das UI aktualisiert respektive der BusyIndicator sichtbar.
    • IP-Adresse ist Registriert
  • 31. Mrz 2015 12:40 Antwort zu

    • kermitfrosch
    • Top 200 Mitwirkender
    • Registriert am 30. Mrz 2015
    • Beiträge 7
    • Punkte 125

    BusyIndicator

    Hallo,

    danke für die schnelle Antwort.
    Der folgende Code ist natürlich Quatsch. Da werden natürlich
    reelle Daten generiert.

    for (int i = 0; i < 150; i++)
    {
          Thread.Sleep(50);
    }


    Aber wie kann ich denn meinen UI Thread aktualisieren ?
    • IP-Adresse ist Registriert
  • 31. Mrz 2015 14:08 Antwort zu

    • MitchMurder
    • Top 100 Mitwirkender
    • Registriert am 04. Dez 2014
    • Berlin
    • Beiträge 16
    • Punkte 245

    BusyIndicator

    Ich würde in den Klassen AViewModel/BViewModel folgenden Aufruf
    DispatcherHelper.UIDispatcher.InvokeAsync
    entfernen.

    Wenn du dir mal die Hilfe zu DispatcherHelper anschaust, liest du folgendes: Helper class for dispatcher operations on the UI thread.
    Und genau das willst du doch gar nicht. Dein Command soll im Hintergrund laufen, der Main- bzw. UI-Thread bleibt frei.

    Beispiel:
    Du ersetzt das Assignment in Line:21 in AViewModel.cs und BViewModel.cs durch folgendes:
    worker.DoWork += ((sender, e) =>
    
                {
    
                    for (int i = 0; i < 150; i++)
    
                    {
    
                        System.Console.WriteLine(i);
    
                        Thread.Sleep(50);
    
                    }
    
                });
    Dann siehst du in VS in der Console die Ausgabe von i und dein Tool zeigt dir den BusyIndicator an, bis der Task erledigt ist.

    Dank Datenbindung musst du nicht direkt aus deinem ViewModel auf den View zugreifen, d.h. eine manuelle Aktualisierung des UI ist bei MVVM i.d.R. nicht notwendig.
    • IP-Adresse ist Registriert
  • 01. Apr 2015 8:15 Antwort zu

    • kermitfrosch
    • Top 200 Mitwirkender
    • Registriert am 30. Mrz 2015
    • Beiträge 7
    • Punkte 125

    BusyIndicator

    Perfekt. So funktionierts
    Danke
    • IP-Adresse ist Registriert
  • 07. Apr 2015 11:47 Antwort zu

    BusyIndicator

    Sehr gut!
    Es funktioniert.Music
    • IP-Adresse ist Registriert
Seite 1 von 1 (13 Treffer)

Regeln | Impressum