You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在WPF程序的Play方法中等待RollButton按钮点击?

解决WPF中等待按钮点击的问题

首先得指出你代码里的两个关键问题:

  1. 原Play()方法里的do-while循环会直接卡死UI线程——因为UI线程被无限循环占用,根本没时间处理按钮点击事件。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 19:50:25