0

我试图让一个程序发布一堆文本。用户输入文本、消息数量以及必须以多快的速度传递这些消息。当程序很忙时,按钮文本需要是“停止”而不是“开始”。当您在最初启动它后按下按钮强制它停止时,文本会变回“开始”,但是当程序在传递给定数量的消息后停止时不会发生这种情况,即使代码已到位并且不会产生错误。

我有一种感觉,这是因为文本由于某种原因没有更新。我试图用 Invalidate() 和 Update() 刷新它,但这不起作用。如何解决这个问题?

这是代码:

private void button1_Click(object sender, EventArgs e)
    {
        if (button1.Text == "Start")
        {
            isEvil = true;
            button1.Text = "Stop";

            Thread t = new Thread(StartTyping);
            t.Start(textBox1.Text);
        }
        else
        {
            isEvil = false;
            button1.Text = "Start";
        }
    }

    private void StartTyping(object obj)
    {
        string message = obj.ToString();
        int amount = (int)numericUpDown2.Value;
        Thread.Sleep(3000);


        for (int i = 0; i < amount; i++)
        {
            if (isEvil == false)
            {
                //////This does NOT work
                //button1.Text = "Start";
                //button1.Invalidate();
                //button1.Update();
                //button1.Refresh();
                //Application.DoEvents();
                break;
            }

            SendKeys.SendWait(message + "{ENTER}");
            int j = (int)numericUpDown1.Value * 10;
            Thread.Sleep(j);
        }
    }
4

5 回答 5

2

您有四个答案告诉您从 UI 线程更新 UI 内容,但它们都没有解决您的代码的逻辑流问题。

它没有发生的原因是因为它只发生在 for 循环when isEvilis false。什么时候isEvil设置false?仅当您单击“停止”时,其他任何地方都没有。

如果您希望按钮在线程完成后返回“开始”,而不单击“停止”,那么您需要在循环之后添加代码来执行此操作,与 : 的值无关isEvil(搭载 VoidMain 的答案)

private void StartTyping(object obj)
{
    string message = obj.ToString();
    int amount = (int)numericUpDown2.Value;
    Thread.Sleep(3000);

    for (int i = 0; i < amount; i++)
    {
        if (isEvil == false)
        {
            if (button1.InvokeRequired)
            {
                button1.BeginInvoke( new Action(() => { button1.Text = "Start"; }) );
            }
            else
            {
                button1.Text = "Start";
            }
            break;
        }

        SendKeys.SendWait(message + "{ENTER}");
        int j = (int)numericUpDown1.Value * 10;
        Thread.Sleep(j);
    }

    if (button1.InvokeRequired)
    {
        button1.BeginInvoke( new Action(() => { button1.Text = "Start"; }) );
    }
    else
    {
        button1.Text = "Start";
    }
}

现在你有重复的代码,所以你可能想把它拆分成一个单独的方法。

于 2012-09-26T22:31:09.627 回答
0

您需要在 UI 线程上更新 UI。

尝试一种叫做SynchronizationContext的东西。当你用谷歌搜索时,有很多例子。

如果您在WPFSilverlight中,则可以使用Dispatcher。同样,如果您在 google 或 StackOverflow 中搜索这些关键字,则会有很多示例。

于 2012-09-26T21:58:59.263 回答
0

您必须从 UI 线程更新您的控件。这就是你为winforms做的方式。

    for (int i = 0; i < amount; i++)
    {
        if (isEvil == false)
        {
            button1.Invoke(new Action(() => button1.Text = "Start"));
            break;
        }

        SendKeys.SendWait(message + "{ENTER}");
        int j = (int)numericUpDown1.Value * 10;
        Thread.Sleep(j);
    }

这将阻止直到 button1 更新其文本。如果您不希望它阻止,请替换InvokeBeginInvoke

于 2012-09-26T22:00:52.613 回答
0

这样的东西(未经测试)应该可以工作:

private void StartTyping(object obj)
{
    string message = obj.ToString();
    int amount = (int)numericUpDown2.Value;
    Thread.Sleep(3000);


    for (int i = 0; i < amount; i++)
    {
        if (isEvil == false)
        {
            if(button1.InvokeRequired)
            {
                button1.BeginInvoke( new Action(() => { button1.Text = "Start"; }) );
            }
            else
            {
                button1.Text = "Start";
            }
            break;
        }

        SendKeys.SendWait(message + "{ENTER}");
        int j = (int)numericUpDown1.Value * 10;
        Thread.Sleep(j);
    }
}
于 2012-09-26T22:02:56.153 回答
0

你最好的选择是使用BackgroundWorker。在这里添加一个简洁的示例有点太笨拙了,但是O'Reilly 提供了一个不错的教程

于 2012-09-26T22:15:49.167 回答