如何在不导致InvalidOperationException的情况下延迟iccommand的执行

本文关键字:情况下 延迟 iccommand 执行 InvalidOperationException | 更新日期: 2023-09-27 17:50:37

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

这是在瓷砖上放置石头的命令:

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

我已经编写了一个AI,当轮到玩家2时放置石头:

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

这工作得很好。然而,我希望ai在2秒后做出动作,而不是立即。

我已经尝试实现这样的延迟:

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

但这导致ClickCommandCanExecuteChanged(this, new EventArgs())行的InvalidOperationException(我在第一个代码示例中的相关行中放置了一个箭头)。这将在2秒后发生(只要Task。继续拖延)。

我该如何解决这个问题?

如何在不导致InvalidOperationException的情况下延迟iccommand的执行

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

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

根据设置,如果您正在使用适当的ViewModel,您可能会选择在ViewModel基类中的UI线程上引发PropertyChanged,因为大多数时候响应该事件的主要原因是更新UI。

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

  Task.Delay(2000).ContinueWith(_ =>
  {
      rowDataContexts[nextMove.Y].SquareDataContexts[nextMove.X].SquareViewModel.Click.Execute(true);
  }, TaskScheduler.FromCurrentSynchronizationContext());