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

C#中如何等待后台计时器驱动的卡片移动进程完成?

解决WinForm卡片移动后的等待逻辑问题

我明白你的问题了——你现在卡在WinForm里卡片移动的时序问题上:卡片移动靠后台计时器的Tick事件驱动,但你需要等卡片完全到位、加入新Deck后再执行后续的卡片比较逻辑,还不能阻塞计时器的运行。之前的while循环无效,核心原因是它把UI线程彻底卡死了——WinForm的计时器Tick事件是在UI线程触发的,线程被循环占住后,计时器根本没机会执行卡片移动的逻辑,AwaitingRecieving自然永远不会变成0。

下面给你两种不用手动管理多线程的简单解决方案:

方法一:用async/await异步等待(推荐)

这种方式不会阻塞UI线程,让计时器能正常处理卡片移动,同时每隔一段时间检查状态直到满足条件:

private async void buCompW1W2_Click(object sender, EventArgs e)
{
    // 启动卡片移动
    DeckPOne.MoveCardFromTopToTop(WarPOne);
    DeckPTwo.MoveCardFromTopToTop(WarPTwo);

    // 等待卡片完成移动:每隔一个计时器周期检查一次状态
    // 把100替换成你的计时器Interval值(比如你的计时器是每50ms Tick一次就写50)
    while (WarPOne.AwaitingRecieving != 0 || WarPTwo.AwaitingRecieving != 0)
    {
        await Task.Delay(100);
    }

    // 现在卡片已经到位,执行后续比较逻辑
    switch (CompareCards(WarPOne.TopCard, WarPTwo.TopCard))
    {
        case -1:
            tbRecord.Text += "\n error comparing";
            break;
        case 1:
            tbRecord.Text += "\n P1 won.";
            break;
        case 2:
            tbRecord.Text += "\n P2 won.";
            break;
        case 0:
            tbRecord.Text += "\n WAR!";
            for (int i = 0; i < 3; i++)
            {
                DeckPOne.MoveCardFromTopToTop(WarPOne);
                DeckPTwo.MoveCardFromTopToTop(WarPTwo);
            }
            break;
    }
}

原理说明

async/await会让等待过程中UI线程解放出来,继续处理计时器Tick、界面刷新等操作;Task.Delay只是在指定时间后重新执行循环检查,不会阻塞线程。等两个Deck的AwaitingRecieving都变为0,就说明卡片移动完成了。

方法二:利用现有计时器的Tick事件检查状态

如果你不想用异步语法,可以直接复用驱动卡片移动的计时器,在每次Tick时检查是否满足执行后续逻辑的条件:

// 标记是否在等待卡片移动完成
private bool _waitingForCards = false;

private void buCompW1W2_Click(object sender, EventArgs e)
{
    // 启动卡片移动
    DeckPOne.MoveCardFromTopToTop(WarPOne);
    DeckPTwo.MoveCardFromTopToTop(WarPTwo);

    // 设置标记,告诉计时器需要等待卡片到位
    _waitingForCards = true;
}

// 你的计时器Tick事件方法(替换成你实际的计时器方法名)
private void cardMovementTimer_Tick(object sender, EventArgs e)
{
    // 保留你原来处理卡片移动的逻辑
    // ... 这里是你原来写的卡片位置更新、加入Deck的代码 ...

    // 检查是否在等待卡片,且卡片已经到位
    if (_waitingForCards && WarPOne.AwaitingRecieving == 0 && WarPTwo.AwaitingRecieving == 0)
    {
        _waitingForCards = false;
        // 执行后续比较逻辑
        RunCardComparison();
    }
}

private void RunCardComparison()
{
    switch (CompareCards(WarPOne.TopCard, WarPTwo.TopCard))
    {
        case -1:
            tbRecord.Text += "\n error comparing";
            break;
        case 1:
            tbRecord.Text += "\n P1 won.";
            break;
        case 2:
            tbRecord.Text += "\n P2 won.";
            break;
        case 0:
            tbRecord.Text += "\n WAR!";
            for (int i = 0; i < 3; i++)
            {
                DeckPOne.MoveCardFromTopToTop(WarPOne);
                DeckPTwo.MoveCardFromTopToTop(WarPTwo);
            }
            break;
    }
}

原理说明

按钮点击只负责启动移动和设置等待标记,剩下的交给计时器本身。每次Tick时先处理卡片移动,再检查是否满足条件,满足就执行后续逻辑并清除标记,完全不影响计时器的正常运行。

这两种方法都能解决你的问题,而且都不用手动创建和管理额外线程,非常适合WinForm的UI场景。

内容的提问来源于stack exchange,提问作者Petr Klíč

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:02:24