2017-03-21 27 views
2

UWPアプリでイベントループ(メインループ)を設定するにはどうすればよいですか?UWPアプリケーションのイベントループを設定する

私の目標は、継続的に更新される計算を持つメインページを持ち、ページ上のイメージを継続的に更新するアプリケーションを持つことです。これが絶えず行われている間、ユーザーは計算動作を変更するためにボタンをクリックしたり、2番目のページに行き、関連するデータを編集することができます。

ユーザーは、メインページに戻ってクリックすると、イメージが表示され、計算が再開され、継続的に更新されます。 (計算は複雑なので、できるだけ早く実行し、可能な限り多くのアプリ時間を使います)。

イベントループなしでこれを実現する方法がある場合は、私もそのことを知りたいと思いますが、これまでのところ私は方法を見つけていません。
イベントループを使用すると、毎回ループを介して計算とUIを更新できます。しかし、私はそうする方法を見つけていません。 This questionはほぼ同じことを尋ねましたが、決して直接答えられず、とにかく異なるユースケースを持っていました。

私は解決策を発見した最も近いループを作成するためにCoreWindowからCoreDispatcherをつかむとRunIdleAsync()方法を使用することです:

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); 
     } 

    }); 
}  

この主な問題は、あなたが間に切り替えることができないということですページ(すでにディスパッチされたイベント内のディスパッチイベントからシステム例外が発生します)。
第2に、これは非常に乱雑であり、イベントループで余分な状態を維持する必要があります。さらに、アプリがユーザーの入力を待っている間に何らかの計算が行われるようにするために、なぜ私はこれらの歪みを通らなければならないのですか?

これを行う方法はありますか(C++ DirectXアプリケーションに切り替える以外に)?

答えて

3

独自のイベントループの設定についてはわかりませんが、そうする必要はありません。

あなたの話は、Taskの素晴らしいケースのようです。ユーザーが何か作業をしたときにいつでも計算タスクを開始し、操作の途中で更新が必要な場合は、標準のC#イベントを使用して進行状況をレポートします。これらの更新では、ビュー・モデル内のプロパティーが変更され、バインディング・システムがそれを取得します。

計算コードをキャンセルして、前回の計算を中止することもできます。

このすべてには、かなり標準的なUWPの概念が含まれています。特別なイベントループの必要はありません。 MVVMとマルチスレッド/タスクを勉強する必要があると私は思っています。あなたはまだ非常に "Win-Forms"のような方法で考えています。

+0

私はMVVMについてもっと勉強する必要があるでしょう。私が達成したいことの種類に対応する参考資料を提案することはできますか? Microsoftのドキュメントはこれをうまくやっていません。 – mlt

+0

最初は、これを達成するために非同期タスクを使用しようとしました。私はその仕事をどこから始めるのか分かりました。ユーザーがメインページに切り替えるときにタスクを起動したいが、ユーザーがボタンをクリックして開始する必要はない。私は 'OnLoaded()'メソッドを使って計算を行い、アニメーションを描画しようとしましたが、画面に到達しませんでした( 'OnLoaded()'で止まってしまいました)。 – mlt

+0

@ mltおそらく、バインディング/タスクを正しく使用せず、UIスレッドをブロックしていたからです。私はこれ以外の私の頭の上からの参照を知りません:https://msdn.microsoft.com/en-us/library/hh848246.aspxあなたが達成したいと思う限り; UIスレッドから集中的に作業を続けるだけです。 – BradleyDotNET

0

イベントループやストリームについて話しているなら、.NetにはRxという名前の素晴らしいライブラリがあります。これは役に立ちます。Reactive Extensionsあなたがコントロールにアクセスする必要があるようなイベントが今、UIスレッド上にあることを

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); 

注:あなたは、このような何かを簡単なフローを設定することができます。今度は、バックグラウンド処理にRxを使用するか、または 'TransformBlockを使用してシステム情報を新しい画像に処理します(一度にObserverObservableにすることができます)。その後、UIスレッドに戻る必要があります。

First optionRx Design Guidelines

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)); 

あなたはおそらくまだアイデアがここに同じ、より多くの情報であり、いくつかの観測者と観測にこのチェーンを分割する必要があります。

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)); 

私はUWPMVVMパターンが最も自然な方法でユーザーに通知するためにあなたを助けるであろう、UIとObservableCollection間の結合で動作する可能性を提供しないことに注意してくださいしたいと思います。

関連する問題