2017-03-21 32 views
2

如何在UWP應用程序中設置事件循環(主循環)?爲UWP應用程序設置事件循環

我的目標是讓一個應用程序擁有一個不斷更新計算的主頁,然後不斷更新頁面上的圖像。雖然這種情況經常發生,但用戶可以單擊按鈕來更改計算行爲,或轉到第二頁並編輯相關數據。

用戶可以點擊回主頁面,看到圖像和計算重新啓動並不斷更新。 (計算複雜,所以應儘可能快地使用盡可能多的應用程序時間)。

如果有一種方法可以在沒有事件循環的情況下完成此操作,我想知道這一點,但到目前爲止我還沒有找到方法。
使用事件循環,我可以簡單地通過循環更新計算和UI。但我還沒有找到任何辦法。 This question問幾乎相同的東西,但從來沒有直接回答,並有不同的使用情況。

我已經找到了一個解決方案最接近的是抓住從CoreWindowCoreDispatcher並使用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); 
     } 

    }); 
}  

與此的主要問題是,你不能切換頁面(您在調度事件中發送系統異常)。
其次,這非常混亂,需要在事件循環中保持額外的狀態。此外,爲什麼我必須經歷這些扭曲才能在應用等待用戶輸入時進行一些計算?

有沒有辦法做到這一點(除了切換到C++的DirectX應用程序)?

回答

3

我不知道設置自己的事件循環,但沒有理由這樣做。

你在說什麼聽起來像是一個偉大的案例Task s。每當用戶做了一些事情時,你就可以開始一個計算任務,讓它通過標準的C#事件報告進度,如果你需要中等操作的更新。這些更新會修改您的視圖模型中的綁定系統將會拾取的屬性。

您還可以使您的計算代碼可以取消,以便更改可以中止以前的計算。

所有這些涉及非常標準的UWP概念;不需要特殊的事件循環。你甚至正在考慮讓我覺得你需要學習MVVM和多線程/任務;你仍然在以「Win-Forms」的方式思考。

+0

您可能是對的,我需要更多地研究MVVM。你能否提出一個參考來解決我想要完成的事情?微軟的這些文檔都沒有做到這一點。 – mlt

+0

最初,我確實嘗試使用異步任務來完成此任務。我掛斷了在哪裏開始這項任務。我希望當用戶切換到主頁面時啓動任務,但不要求用戶單擊按鈕啓動它。我嘗試使用'OnLoaded()'方法來進行計算並繪製我的動畫,但它從未到達屏幕(卡在'OnLoaded()')中。 – mlt

+0

@mlt可能是因爲您沒有正確使用綁定/任務並阻止UI線程。除了這個之外,我不知道任何關於我頭頂的參考資料:https://msdn.microsoft.com/en-us/library/hh848246.aspx至於你想完成什麼;只需保留UI線程中的任何密集工作即可。 – BradleyDotNET

0

如果我們正在談論某個事件循環或流,.Net有一個很好的庫,名爲RxReactive Extensions,這可能對您有所幫助。您可以設置一個簡單的流程,這樣的事情:

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

注意的事件,現在都在UI線程,因爲你需要訪問控制。現在您有兩種選擇:使用Rx進行後臺處理,或使用TPL Dataflow'TransformBlock將系統信息處理爲新映像(一次可以爲ObserverObservable)。之後,你需要回到UI線程。

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

你或許應該拆分這條產業鏈分爲幾個觀察員和觀測,仍然是這裏的想法是一樣的,瞭解更多信息: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)); 

我想指出,UWPMVVM模式確實提供了可能性與UI和ObservableCollection之間的綁定工作,這將幫助你以通知用戶在最自然的方式。