如何在WPF程序的Play方法中等待RollButton按钮点击?
解决WPF中等待按钮点击的问题
首先得指出你代码里的两个关键问题:
- 原
Play()方法里的do-while循环会直接卡死UI线程——因为UI线程被无限循环占用,根本没时间处理按钮点击事件。 Dice类的Roll()方法每次都新建Random实例,短时间内多次调用会生成重复的随机数,导致骰子结果可能一直相同。
下面给两种解决方案,从易到难:
方案一:事件驱动(适合初学者)
WPF本身是事件驱动的设计,不用强行写循环等待,直接把游戏逻辑放到按钮点击事件里即可:
第一步:修正Dice类的随机数问题
class Dice { // 用静态Random实例,避免短时间内生成重复随机数 private static readonly Random _random = new Random(); TextBlock diceTextBlock; const int minNumber = 1; const int maxNumber = 6; int number; public int Number { get { return number; } set { number = value; diceTextBlock.Text = number.ToString(); } } public Dice(TextBlock diceTextBlock) { this.diceTextBlock = diceTextBlock; Number = minNumber; } public void Roll() { Number = _random.Next(minNumber, maxNumber + 1); } }
第二步:修改GameWindow逻辑
去掉Play()方法里的循环,直接在按钮点击后判断是否达成游戏结束条件:
public partial class GameWindow : Window { Dice dice1; Dice dice2; int rollCount; public GameWindow() { InitializeComponent(); dice1 = new Dice(Dice1TextBlock); dice2 = new Dice(Dice2TextBlock); rollCount = 0; // 这里不再调用Play(),等待用户主动点击按钮 } private void RollButton_Click(object sender, RoutedEventArgs e) { dice1.Roll(); dice2.Roll(); rollCount++; // 检查是否掷出双数,触发游戏结束 if (dice1.Number == dice2.Number) { MessageBox.Show($"恭喜!你用了{rollCount}次掷出双数!"); // 重置游戏状态 rollCount = 0; dice1.Number = 1; dice2.Number = 1; } } }
这种方式完全贴合WPF的事件模型,逻辑简单直接,初学者容易上手。
方案二:异步等待(贴近你原本的循环思路)
如果想保留Play()方法的循环结构,可以用async/await结合TaskCompletionSource实现“等待按钮点击”的效果,不会阻塞UI线程:
第一步:同样修正Dice类的随机数问题(同方案一)
第二步:修改GameWindow的异步逻辑
public partial class GameWindow : Window { Dice dice1; Dice dice2; int rollCount; // 用来跟踪等待按钮点击的任务 private TaskCompletionSource<bool> _rollClickedTcs; public GameWindow() { InitializeComponent(); dice1 = new Dice(Dice1TextBlock); dice2 = new Dice(Dice2TextBlock); rollCount = 0; // 启动游戏逻辑 Play(); } private async void Play() { do { // 创建新的任务源,等待按钮点击 _rollClickedTcs = new TaskCompletionSource<bool>(); // 异步等待按钮点击完成,不会阻塞UI await _rollClickedTcs.Task; // 点击后执行掷骰子 dice1.Roll(); dice2.Roll(); rollCount++; } while (dice1.Number != dice2.Number); // 游戏结束 MessageBox.Show($"恭喜!你用了{rollCount}次掷出双数!"); rollCount = 0; // 可以再次调用Play()开启新游戏 Play(); } private void RollButton_Click(object sender, RoutedEventArgs e) { // 当按钮被点击时,完成等待任务 _rollClickedTcs?.SetResult(true); } }
这里的核心是TaskCompletionSource:它相当于一个“信号器”,Play()方法里用await等待这个信号,按钮点击时触发信号,Play()就会继续执行下一步。
内容的提问来源于stack exchange,提问作者Jérémie Normand
相关产品推荐
相关产品推荐

