为UWP应用程序设置事件循环

时间:2017-03-21 20:21:47

标签: c# multithreading uwp

如何在UWP应用中设置事件循环(主循环)?

我的目标是让应用程序的主页面具有不断更新的计算,然后不断更新页面上的图像。虽然这种情况不断发生,但用户可以单击按钮更改计算行为,或转到第二页并编辑相关数据。

然后,用户可以单击返回主页面并查看图像并重新开始计算并不断更新。 (计算很复杂,因此应尽可能快地使用尽可能多的应用时间。)

如果有一种方法可以在没有事件循环的情况下实现这一点,我也想知道,但到目前为止我还没找到方法。
通过事件循环,我可以在每次循环时简单地更新计算和UI。但我还没有找到任何办法。 This question问了几乎相同的事情,但是从来没有直接回答过,并且还有一个不同的用例。

我找到的最接近解决方案的方法是从CoreDispatcher抓取CoreWindow并使用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应用程序)?

2 个答案:

答案 0 :(得分:3)

我不知道如何设置自己的事件循环,但没有理由这样做。

你所说的话听起来像是Task的一个很好的案例。您可以在用户执行某项操作时启动计算任务,如果您需要中间操作更新,则通过标准C#事件报告其进度。这些更新将修改视图模型中的属性,然后绑定系统会接收这些属性。

您还可以取消计算代码,因此更改可以中止先前的计算。

所有这些都涉及非常标准的UWP概念;不需要特殊的事件循环。你甚至考虑到这让我觉得你需要学习MVVM和多线程/任务;你还在想着一个非常好的表格"那种方式。

答案 1 :(得分:0)

如果我们正在谈论某些事件循环或流,.Net有一个很棒的库[x y z xx yy zz]Reactive Extensions,这可能对您有所帮助。您可以设置一个简单的流程,如下所示:

Rx

请注意,当前事件位于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' TPL Dataflow用于将系统信息处理为新图像(一次可以TransformBlockObserver)。之后你需要回到UI线程。

First option

Observable

你可能应该把这个链分成几个观察者和观察者,但这个想法是一样的,更多信息在这里:Rx Design Guidelines

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

我想要注意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)); UWP模式确实可以使用UI和MVVM之间的绑定,这将帮助您以最自然的方式通知用户。 / p>