2017-03-21 2 views
2

Wie richte ich eine Ereignisschleife (Hauptschleife) in einer UWP App ein?Einrichten einer Ereignisschleife für eine UWP-App

Mein Ziel ist es, eine App zu haben, die eine Hauptseite mit einer ständig aktualisierenden Berechnung hat, die dann ein Bild auf der Seite fortlaufend aktualisiert. Während dies ständig geschieht, kann der Benutzer auf eine Schaltfläche klicken, um das Berechnungsverhalten zu ändern oder auf eine zweite Seite zu gehen und zugehörige Daten zu bearbeiten.

Der Benutzer kann dann zurück auf die Hauptseite klicken und sehen, dass das Bild und die Berechnung neu starten und kontinuierlich aktualisieren. (Die Berechnung ist komplex, also sollte es so schnell wie möglich gehen und so viel App-Zeit wie möglich verbrauchen).

Wenn es einen Weg gibt, dies ohne eine Ereignisschleife zu erreichen, würde ich das gerne auch wissen, aber bis jetzt habe ich noch keinen Weg gefunden.
Mit einer Ereignisschleife kann ich einfach die Berechnung und Benutzeroberfläche jedes Mal durch die Schleife aktualisieren. Aber ich habe keinen Weg gefunden, dies zu tun. This question gefragt fast das gleiche, aber wurde nie direkt beantwortet und hatte einen anderen Anwendungsfall sowieso.

Die nächstgelegene ich zu einer Lösung gefunden habe, ist die CoreDispatcher vom CoreWindow und verwenden Sie die RunIdleAsync() Methode zu greifen um eine Schleife zu erstellen:

public MainPage() 
{ 
    this.InitializeComponent(); 

    Windows.UI.Core.CoreWindow appwindow = Windows.UI.Core.CoreWindow.GetForCurrentThread(); 
    Windows.UI.Core.CoreDispatcher appdispatcher = appwindow.Dispatcher; 
    //create a continuously running idle task (the app loop) 
    appdispatcher.RunIdleAsync((dummyt) => 
    { 
     //do the event loop here 
     . 
     . 
     . 
     if (appdispatcher.ShouldYield()) //necessary to prevent blocking UI 
     { 
      appdispatcher.ProcessEvents(Windows.UI.Core.CoreProcessEventsOption.ProcessAllIfPresent); 
     } 

    }); 
}  

Das Hauptproblem dabei ist, dass Sie nicht zwischen wechseln Seiten (Sie erhalten eine Systemausnahme vom Versenden von Ereignissen innerhalb eines bereits versendeten Ereignisses).
Zweitens ist dies sehr chaotisch und erfordert die Aufrechterhaltung Extra-Status in der Ereignisschleife. Außerdem, warum sollte ich diese Verrenkungen durchgehen müssen, nur um einige Berechnungen durchzuführen, während die App auf Benutzereingaben wartet?

Gibt es eine Möglichkeit, dies zu tun (neben dem Wechsel zu einer C++ DirectX-App)?

Antwort

3

Ich weiß nicht über die Einrichtung einer eigenen Ereignisschleife, aber es gibt keinen Grund, dies zu tun.

Wovon Sie sprechen, klingt nach einem großartigen Fall für Task s. Sie würden eine Berechnungsaufgabe starten, wenn Ihr Benutzer etwas getan hat, und den Fortschritt über Standard-C# -Ereignisse melden, wenn Sie Aktualisierungen in der Mitte benötigen. Diese Aktualisierungen würden Eigenschaften in Ihrem Ansichtsmodell ändern, die das Bindungssystem dann aufnehmen würde.

Sie könnten Ihren Berechnungscode auch stornieren, damit Änderungen eine vorherige Berechnung abbrechen können.

All dies beinhaltet ziemlich Standard-UWP-Konzepte; keine Notwendigkeit für eine spezielle Ereignisschleife. Dass Sie überhaupt darüber nachdenken, lässt mich denken, dass Sie MVVM und Multithreading/Aufgaben studieren müssen; Sie denken immer noch auf eine sehr "Win-Forms" Art und Weise.

+0

Sie haben wahrscheinlich Recht, dass ich mehr über MVVM lernen muss. Können Sie mir eine Referenz vorschlagen, die auf die Art von Dingen abzielt, die ich erreichen möchte? Keine der Microsoft-Dokumentation leistet gute Arbeit. – mlt

+0

Anfangs habe ich versucht, asynchrone Aufgaben zu verwenden. Ich habe aufgelegt, wo ich diese Aufgabe beginnen soll. Ich möchte, dass die Aufgabe gestartet wird, wenn ein Benutzer zur Hauptseite wechselt, aber nicht, dass der Benutzer auf eine Schaltfläche klicken muss, um ihn zu starten. Ich habe versucht, die 'OnLoaded()' Methode zu benutzen, um die Berechnung durchzuführen und meine Animation zu zeichnen, aber sie erreichte nie den Bildschirm (blieb in 'OnLoaded()' hängen). – mlt

+0

@mlt Wahrscheinlich, weil Sie die Bindungen/Aufgaben nicht korrekt verwendet und den UI-Thread blockiert haben. Ich kenne keine Hinweise von oben auf meinen Kopf neben diesem: https://msdn.microsoft.com/en-us/library/hh848246.aspx Soweit was Sie erreichen möchten; Behalte einfach jede intensive Arbeit aus dem UI-Thread. – BradleyDotNET

0

Wenn es sich um eine Ereignisschleife oder einen Stream handelt, enthält .Net eine große Bibliothek namens Rx oder Reactive Extensions, die für Sie hilfreich sein kann. Sie können einen einfachen Fluss, so etwas wie diese ein:

var source = Observable 
    // fire event every second 
    .Interval(TimeSpan.FromSeconds(1), Scheduler.DispatcherScheduler) 
    // add timestamp for event 
    .Timestamp() 
    // gather system information to calculate 
    .Select(GetSystemInfo); 

Beachten Sie, dass die Ereignisse jetzt auf UI-Thread sind, wie Sie die Steuerelemente zugreifen müssen. Jetzt haben Sie zwei Möglichkeiten: Verwenden Sie Rx auch für die Hintergrundverarbeitung oder verwenden Sie TPL Dataflow 'TransformBlock für die Verarbeitung Ihrer Systeminformationen in ein neues Bild (es kann gleichzeitig Observer und Observable sein). Danach müssen Sie zum UI-Thread zurückkehren.

First option:

var source = Observable 
    // fire event every second 
    .Interval(TimeSpan.FromSeconds(1), DispatcherScheduler.Current) 
    // add timestamp for event 
    .Timestamp() 
    // gather system information to calculate 
    .Select(GetSystemInfo) 

    // expensive calculations are done in background 
    .Select(x => x.ObserveOn(DefaultScheduler.Instance)) 
    .Select(x => Expensive(x)) 

    .Select(x => x.ObserveOn(DispatcherScheduler.Current)) 
    .Select(x => UpdateUI(x)); 

Sie sollten wahrscheinlich diese Kette in mehrere Beobachter und Observablen gespalten, noch die Idee ist die gleiche, mehr Informationen hier: Rx Design Guidelines.

Second option:

var action = new TransformBlock<SystemInfo, ImageDelta>(CalculateDelta, 
    new ExecutionDataflowBlockOptions 
    { 
     // we can start as many item processing as processor count 
     MaxDegreeOfParallelism = Environment.ProcessorCount, 
    }); 

IDisposable subscription = source.Subscribe(action.AsObserver()); 

var uiObserver = action.AsObservable() 
    .Select(x => x.ObserveOn(DispatcherScheduler.Current)) 
    .Select(x => UpdateUI(x)); 

ich anmerken möchte, dass UWP und MVVM Muster bieten haben eine Möglichkeit mit der Bindung zwischen UI zu arbeiten und ObservableCollection, die Ihnen helfen wird, Benutzer in natürlichste Art zu informieren.