2016-10-18 2 views
1

Ich versuche, eine einfache App, die ich auf Windows Phone 8 auf Universal Windows ausgeführt hatte, zu portieren. Ich habe ein paar Dateien, die ich (lokal) laden muss, bevor ich den Hauptrahmen/die Haupseite erstelle, da diese anweisen, wie man die Seite an erster Stelle erstellt. Es gibt eine .XML- und einige Inhaltsdateien, die Teil von Assets sind.Universal Windows, C#, erwarten während App-Initialisierung

Ich habe die Initialisierung während der App.Application_Launching() durchgeführt, die ich jetzt denke, wird von App.OnLaunched() ersetzt. Das Problem liegt in der neuen asynchronen Datei-IO. Ich kann keinen Ort finden, an dem ich Async-APIs aufrufen kann, ohne dass das Programm hängen bleibt. Es scheint, dass irgendwo in App.OnLaunched(), MainPage.MainPage(), MainPage.OnNavigatedTo() usw. kann ich nicht erwarten.

Ich muss im Grunde ein Hintergrund-Thread abfeuern, um eine Aufgabe zu planen, die später ausgeführt wird, um die eigentliche Initialisierung auszuführen, und dann zurück in den MainPage-Pool zu rufen, um etwas korrekt auszuführen. Der resultierende Code sieht ungefähr wie folgt aus. Scheint übermäßig komplex, aber ich denke, das ist richtig?

Danke, Nick.

public partial class MainPage : Page 
{ 
    // Constructor 
    public MainPage() 
    { 
     InitializeComponent(); 

     // This doesn't work ... 
     // var task = InitAsync(); 
     // task.Wait() 


     // This seems to ... 
     IAsyncAction asyncAction = ThreadPool.RunAsync((workItem) => 
     { 
      var ignored = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,() => 
      { 
       TryInitAsync(); 
      }); 

     }); 

    } 

    private async void TryInitAsync() 
    { 
     try 
     { 
      await InitAsync(); 
     } 
     catch 
     { 
      int foo = 0; 
     } 
    } 

    private async Task<Boolean> InitAsync() 
    { 
     // Things that go await in the night 

     // Other things that update the layout 

     return true; 
    } 
} 

Antwort

0

scheint zu komplex, aber ich denke, das ist richtig?

Nein, das würde ich nicht sagen.

Ich kann keinen konkreten Hinweis zur Initialisierung selbst geben, da diese Angaben in Ihrer Frage fehlen. Die grundlegende Strategie besteht darin, dass die Benutzeroberfläche nicht initialisierte Daten toleriert und die Initialisierung asynchron ausführt und die Eigenschaften nach Bedarf aktualisiert.

Soweit Ihre spezifischen Mittel zum Starten der asynchronen Initialisierung gehen, haben Sie es komplizierter gemacht, als es sein muss oder sollte. Dies wäre besser:

public MainPage() 
{ 
    InitializeComponent(); 

    var ignored = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow 
     .Dispatcher.RunAsync(CoreDispatcherPriority.Normal,() => TryInitAsync()); 
} 

I.e. Es ist nicht erforderlich, eine Hintergrundaufgabe mit ThreadPool.RunAsync() zu starten, wenn Sie lediglich den Aufruf der Methode TryInitAsync() aufschieben und ihn auf dem UI-Thread aufrufen.

Wenn Sie dies (oder Ihren komplizierteren Weg) tun, blockieren Sie dennoch den UI-Thread. Es wäre sogar besser, nichtDispatcher.RunAsync() zu verwenden. Stattdessen tun Anruf TryInitAsync() direkt von einem Hintergrund-Task (z. B. rufen Sie es mit ThreadPool.RunAsync()) und haben die UI-gebundenen Eigenschaften abhängig von der Initialisierung aktualisiert asynchron während der Initialisierung fortschreitet.

+0

Ah, das ist es, was ich suchte. Im Prinzip etwas, das zu einem späteren Zeitpunkt auf dem UI-Thread geplant werden kann. – user3799309

+0

_ "etwas, das zu einem späteren Zeitpunkt auf dem UI-Thread zurückgestellt werden kann" _ - das ist die Methode 'RunAsync()' des Dispatchers. Es ist nicht der beste Weg, weil das den UI-Thread immer noch blockieren wird (genau wie beim direkten Aufruf vom Konstruktor), aber es könnte für Sie funktionieren. –

1

Es scheint, dass irgendwo in App.OnLaunched(), MainPage.MainPage(), MainPage.OnNavigatedTo() usw. kann ich nicht erwarten.

Der Kern konzeptionelle Veränderung ist, dass moderne Anwendungen Muss zeigen eine Art von UI sofort (die synchron bedeutet). Aus diesem Grund können Sie I/O beim Start nicht ausführen.

So haben Sie darüber nachdenken, was Ihre App wie aussehen sollten, bevor es alle Dateien lädt, zeigen diesen Zustand sofort und auch asynchronen Laden Ihres „echten“ UI starten.

könnten Sie rufen TryInitAsync direkt von Ihrem Konstruktor:

public MainPage() 
{ 
    InitializeComponent(); 
    TryInitAsync(); 
} 

Oder, wenn Sie Ihre UI mit Datenbindung aktualisieren, können Sie meine verwenden NotifyTask<T> type:

public NotifyTask<InitData> Data { get; } 
public MainPage() 
{ 
    InitializeComponent(); 
    Data = NotifyTask.Create(InitAsync()); 
} 
private async Task<InitData> InitAsync() { ... } 

Und dann können Sie Datenbindung an Data.Result um InitData oder Data.IsCompleted/Data.IsNotCompleted zu erhalten, um den ursprünglichen "loading ..." Status anzuzeigen/auszublenden.

+0

Ich hatte anfangs versucht, InitAsync() direkt aufzurufen, aber wenn man es synchron macht, würde das Programm hängen bleiben (obwohl es manchmal funktionieren würde, wenn man im Debugger durchgeht). Ja, ich habe ein Standard-Layout, das sofort angezeigt wird, obwohl es momentan nur "Laden" heißt. Ich schaue mir die NotifyTask an. – user3799309

+0

@ user3799309: In meinem Code wird 'InitAsync' direkt aufgerufen, aber es ist nicht synchron. –

Verwandte Themen