首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在不导致InvalidOperationException的情况下延迟ICommand执行?

如何在不导致InvalidOperationException的情况下延迟ICommand执行?
EN

Stack Overflow用户
提问于 2015-05-25 21:49:05
回答 2查看 265关注 0票数 1

我正在编写一个WPF 'Reversi‘游戏,在游戏中,玩家按下一个8x8网格的瓷砖来放置一块石头。

这是将一块石头放在瓷砖上的命令:

代码语言:javascript
复制
private class Click : ICommand
    {
        private readonly SquareViewModel squareViewModel;

        public ClickCommand(SquareViewModel squareViewModel)
        {
            this.squareViewModel = squareViewModel;

            squareViewModel.Square.IsValidMove.PropertyChanged += (sender, args) =>
            {
                if (CanExecuteChanged != null)
                {
  /*->*/            CanExecuteChanged(this, new EventArgs());
                }
            };
        }

        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return squareViewModel.Square.IsValidMove.Value;
        }

        public void Execute(object parameter)
        {
            squareViewModel.Square.PlaceStone();
        }
    }

我已经编写了一个人工智能程序,当轮到2号玩家时,它会放置一块石头:

代码语言:javascript
复制
void CurrentPlayer_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
          Player player = ((ICell<Player>)(sender)).Value;
          if (player != null && player.Equals(Player.TWO))
          {
               Vector2D nextMove = ai.FindBestMove(boardViewModel.Game);
               rowDataContexts[nextMove.Y].SquareDataContexts[nextMove.X].SquareViewModel.Click.Execute(null);
           }
        }
    }

这可以很好地工作。但是,我希望人工智能在2秒后移动,而不是立即移动。

我尝试过像这样实现一个延迟:

代码语言:javascript
复制
void CurrentPlayer_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
          Player player = ((ICell<Player>)(sender)).Value;
          if (player != null && player.Equals(Player.TWO))
          {
              Vector2D nextMove = ai.FindBestMove(boardViewModel.Game);
              Task.Delay(2000).ContinueWith(_ =>
                  {
                      rowDataContexts[nextMove.Y].SquareDataContexts[nextMove.X].SquareViewModel.Click.Execute(true);
                  });
          }
    }

但这会在ClickCommand中的CanExecuteChanged(this, new EventArgs())行生成一个InvalidOperationException (我在第一个代码示例中的相关行上放了一个箭头)。这在2秒后发生(只要Task.Delay继续)。

我该如何解决这个问题呢?

EN

回答 2

Stack Overflow用户

发布于 2015-05-25 21:55:57

异常是由在非UI线程上执行命令引起的,因为现在它是由线程池中的线程执行的任务的一部分。

要使其工作,请切换到任务或ViewModel中的UI线程。

根据设置的不同,如果您使用的是正确的ViewModel,您可能会选择在ViewModel基类中的UI线程上引发PropertyChanged,因为大多数情况下响应该事件的主要原因是为了更新UI。有关如何实现这一点,请参阅https://stackoverflow.com/a/24882812/563088

票数 3
EN

Stack Overflow用户

发布于 2019-12-19 11:02:42

现在,使用.Net Framework4.6.1,您可以通过添加如下所示的TaskScheduler.FromCurrentSynchronizationContext()参数来指示要在当前上下文中运行线程的任务:

代码语言:javascript
复制
  Task.Delay(2000).ContinueWith(_ =>
  {
      rowDataContexts[nextMove.Y].SquareDataContexts[nextMove.X].SquareViewModel.Click.Execute(true);
  }, TaskScheduler.FromCurrentSynchronizationContext());
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30439916

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档