Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在不导致InvalidOperationException的情况下延迟ICommand执行?_C#_Wpf_Asynchronous_Delay_Icommand - Fatal编程技术网

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

C# 如何在不导致InvalidOperationException的情况下延迟ICommand执行?,c#,wpf,asynchronous,delay,icommand,C#,Wpf,Asynchronous,Delay,Icommand,我正在编写一个WPF“Reversi”游戏,在这个游戏中,玩家按8x8网格中的一块瓷砖来放置一块石头 这是将石头放置在瓷砖上的命令: private class Click : ICommand { private readonly SquareViewModel squareViewModel; public ClickCommand(SquareViewModel squareViewModel) { this

我正在编写一个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);
           }
        }
    }
这个很好用。然而,我希望人工智能在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);
                  });
          }
    }
但这会导致ClickCommand中带有CanExecuteChangedthis的行出现InvalidOperationException。我在第一个代码示例的相关行中放置了一个箭头。这会在任务完成2秒后发生。延迟继续


如何解决此问题?

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

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

根据设置,如果您使用的是正确的ViewModel,您可能会选择在ViewModel基类中提升UI线程上的PropertyChanged,因为大多数时候响应该事件的主要原因是更新UI。
有关如何实现此功能,请参见。

在非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());
现在,使用.Net framework 4.6.1,您可以通过添加TaskScheduler.FromCurrentSynchronizationContext参数来指示要在当前上下文中运行线程的任务,如下所示:

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