c#UWP如何安排在当前Dispatcher.ProcessEvents()之后运行的东西?它甚至可能吗?

时间:2017-03-23 01:25:20

标签: c# uwp win-universal-app

我正在尝试创建一个非常简单的“游戏引擎”,以便在通用平台和Win2D中玩游戏。

我想创建一个可以启动和停止的“主游戏循环”。

public async void StartGameLoop()
{           
    await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
    {
        GameLoopStopSignal = false;
        while (!GameLoopStopSignal)
        {
            //something like good old DoEvents()?
            CoreApplication.MainView.CoreWindow.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessAllIfPresent);

            //Game Tick
            Tick();
        }
    });
}
public void StopGameLoop()
{
    GameLoopStopSignal = true;
}

如果我在某个页面的“已加载”事件中调用StartGameLoop(),那么一切都像魅力一样。

private void Page_Loaded(object sender, RoutedEventArgs e)
{
    StartGameLoop();//all good
}

但是如果我在按钮的“click”事件中调用StartGameLoop(),我会遇到一个灾难性的失败异常,说明“不允许对ProcessEvents方法进行嵌套调用。”,女巫实际上可以有所帮助。

private void Button_Click(object sender, RoutedEventArgs e)
{
    StartGameLoop();//will cause exception on Dispatcher.ProcessEvents()
}

因此,当我点击那些UI按钮时,我正在寻找一种方法来确保游戏循环在任何可能正在运行的ProcessEvents()调用之后启动...我想出了新的想法:)

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

尝试await Task.Yield();

这告诉调度员在完成处理后处理后的任何事情。这不能得到保证......调度员会决定优先级,但请尝试一下,看看它是否符合您的要求。

https://msdn.microsoft.com/en-us/library/system.threading.tasks.task.yield(v=vs.110).aspx

举个例子,试试这个:

await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.High, async () =>
{
    GameLoopStopSignal = false;
    while (!GameLoopStopSignal)
    {
        //something like good old DoEvents()?
        CoreApplication.MainView.CoreWindow.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessAllIfPresent);

        await Task.Yield();
        //Game Tick
        Tick();
    }
});

请注意async () => {...}方法中的RunAsync

答案 1 :(得分:0)

最后我恢复使用Task.Run()(因此在线程池上运行主循环)而不是在CoreWindow.Dispatcher上运行(在主UI线程中);似乎绕过了我遇到的所有问题。不确定它最终会回来咬我但手指交叉。

public void StartGameLoop()
{           
    Task.Run(() =>
    {
        GameLoopStopSignal = false;
        clock.Start();
        while (!GameLoopStopSignal)
        {
            Tick();
        }
        clock.Stop();
    });
}