简体   繁体   English

文本框未更新

[英]TextBox not being updated

I have a textBox2 on my windows form (confirmed name & spelling) I drug a timer from the toolbox over to my windows form and it is named timer1. 我在Windows窗体上有一个textBox2(确认名称和拼写),我将一个定时器从工具箱放到Windows窗体中,并将​​其命名为timer1。 I am trying to have the timer begin when the button is pressed and have textBox2 show each incrementing second so it shows a running time of how long the entire process has taken. 我试图让计时器在按下按钮时开始计时,并让textBox2显示每个递增的秒数,以便它显示整个过程花费了多长时间的运行时间。 Where did I err? 我在哪里错了?

public partial class Form1 : Form
{
    private int duration = 0;
    private void button1_Click(object sender, EventArgs e)
    {
        timer1.Enabled = true;
        timer1.Start();
        First();
        Second();
        Thirds();
        Fourth();
        Fifth();
        timer1.Stop();
    }
    private void timer1_Tick(object sender, EventArgs e)
    {
        duration++;
        textBox2.Text = duration.ToString();
    }
}

It's not clear what the methods First() , Second() , and so on represent. 目前尚不清楚First()Second()等方法代表什么。 But based on the rest of the code, it seems likely those are long-running tasks that you are trying to time. 但是根据其余代码,您似乎很可能在尝试长时间运行这些任务。

In any case, the problem is that you never return from the button1_Click() method until after you've stopped the timer. 无论如何,问题在于,直到停止计时器后,您才可以从button1_Click()方法返回。 The timer ticks are raised in the UI thread, and can only be raised if the UI thread is not blocked by the handling of some other event. 计时器滴答声在UI线程中引发,并且仅在UI线程未被其他事件处理阻止时才引发。 Like the handling of button1 's Click event. 就像处理button1Click事件一样。

You should be executing your long-running operations in a separate thread, eg using Task . 您应该在单独的线程中执行长时间运行的操作,例如使用Task Then the timer will work correctly, or you can even just use a loop in an async method to display the elapsed time, whichever you prefer. 然后计时器将正常工作,或者您甚至可以使用async方法中的循环来显示经过的时间,无论您选择哪个。

For example: 例如:

private int duration = 0;
private async void button1_Click(object sender, EventArgs e)
{
    timer1.Enabled = true;
    timer1.Start();

    await Task.Run(() =>
    {
        First();
        Second();
        Thirds();
        Fourth();
        Fifth();
    });

    timer1.Stop();
}

private void timer1_Tick(object sender, EventArgs e)
{
    duration++;
    textBox2.Text = duration.ToString();
}

Notes: 笔记:

  • The await feature, new to C# 5.0, is used in the example above. 上面的示例中使用了C#5.0的新增功能- await功能。 See below for a different approach that is compatible with older versions of C# and .NET. 请参阅以下有关与C#和.NET的较早版本兼容的不同方法。
  • When using await , the async method in which the statement is contained will execute up to the "awaited" expression. 使用await ,包含该语句的async方法将一直执行到“ awaited”表达式。 At that point, control of the thread is yielded back to the caller of the async method. 那时,线程的控制权被交还给async方法的调用者。 Later, when the awaited expression finally completes, control of the thread is returned back to the async method at the point where it previously yielded (ie the await statement). 稍后,当等待的表达式最终完成时,线程的控制权在先前产生的点返回给async方法(即, await语句)。
  • In the above, what that means is that your five methods, wrapped in the Task , are executed asynchronously in a different thread. 在上面,这意味着包装在Task中的五个方法在另一个线程中异步执行。 When that Task is started, the button1_Click() method actually returns to its caller. 启动该Task时, button1_Click()方法实际上返回其调用方。 If and when they (ie that Task ) finally complete, execution of the button1_Click() method will resume, at the next statement: timer1.Stop() . 如果它们(即那个Task )最终完成,当它们完成时,将在下timer1.Stop()语句timer1.Stop()处继续执行button1_Click()方法。


The async / await feature makes code that uses asynchronous operations a lot easier to write. async / await功能使使用异步操作的代码更容易编写。 But even before that, there are other mechanisms to do the same thing. 但即使在此之前,还有其他机制可以做同样的事情。 Here is one such mechanism, using the BackgroundWorker object: 这是一种使用BackgroundWorker对象的机制:

private async void button1_Click(object sender, EventArgs e)
{
    BackgroundWorker worker = new BackgroundWorker();

    worker.DoWork += (sender1, e1) =>
    {
        First();
        Second();
        Thirds();
        Fourth();
        Fifth();
    };

    worker.RunWorkerCompleted += (sender1, e1) =>
    {
        timer1.Stop();
    };

    timer1.Enabled = true;
    timer1.Start();

    worker.RunWorkerAsync();
}

Notes: 笔记:

  • When the BackgroundWorker object is created, it captures the current synchronization context (if any), which will be used later to raise all of the BackgroundWorker events except DoWork . 创建BackgroundWorker对象时,它将捕获当前的同步上下文(如果有),稍后将用于引发除DoWork之外的所有BackgroundWorker事件。
  • The DoWork event is raised using a thread pool thread, ie some thread other than the main UI thread. 使用线程池线程(即主UI线程以外的其他线程)引发DoWork事件。 This allows things to happen on the UI thread even while the long-running work is being executed. 即使执行长时间运行的工作,这也可以使事情发生在UI线程上。
  • The code above might seem a little upside-down. 上面的代码似乎有点颠倒了。 That's because the parts that are executed later, are actually declared earlier as anonymous methods subscribed to the DoWork and RunWorkerCompleted events. 这是因为稍后执行的部分实际上是在声明为DoWorkRunWorkerCompleted事件的匿名方法之前声明的。
  • Having declared those anonymous methods and subscribed them to their events, the code then actually starts the timer, and then the BackgroundWorker itself. 声明了那些匿名方法并为其订阅了事件后,代码实际上将启动计时器,然后启动BackgroundWorker本身。 It is only when the RunWorkerAsync() method is called that the worker starts running, by raising the DoWork event. 只有在调用RunWorkerAsync()方法时,工作程序才会通过引发DoWork事件来开始运行。


By the way, while I left your original code as intact as possible, please do note that you don't need both the timer1.Enabled = true; 顺便说一句,虽然我尽可能保留了原始代码,但请注意,您不需要同时使用timer1.Enabled = true; and the timer1.Start() . timer1.Start() Either suffices to start the timer; 任一都足以启动计时器; you can use whichever one you like and leave out the other. 您可以使用任意一个,而忽略另一个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM