Label不会在while循环中更改值

时间:2010-08-07 17:29:09

标签: c# .net wpf

private void button1_Click(object sender, RoutedEventArgs e)
{
        int i = 0;

        while (i < 500)
        {
            label1.Content = i.ToString();
        //  System.Threading.Thread.Sleep(2000);
            ++i;
        }
 }

每次变量递增时,我都会尝试更新Label的内容,但是只有在while循环终止后,label1的内容才会更改一次。我认为计数器变量的增量是如此之快以至于UI线程无法赶上它,所以我想让线程空闲2秒,希望看到label1更改值500次。它也没用。为什么呢?

5 个答案:

答案 0 :(得分:7)

正如其他人所说,问题在于你正在阻止UI线程。

我建议您使用DispatcherTimer来安排更新,而不是将建议与Application.DoEvents一起使用。示例代码:

DispatcherTimer timer = new DispatcherTimer();
timer.Tick += delegate
{
    label.Content = counter.ToString();
    counter++;
    if (counter == 500)
    {
        timer.Stop();
    }
};
timer.Interval = TimeSpan.FromMilliseconds(2000);
timer.Start();

(我不确定Application.DoEvents是否可以在WPF中运行,而且它通常被认为是不好的做法。如果它 工作,我怀疑它是否可以保证在将来有效为了这个原因,在同一个应用程序中混合使用两个UI听起来对我来说真是个坏主意。)

可以使用TimerSystem.Threading.TimerSystem.Timers.Timer),但在这两种情况下,你都需要编组回调度程序线程。 DispatcherTimer使这更简单 - Tick事件总是在Dispatcher线程中触发。

编辑:如果确实想要等同于DoEvents,那么我验证的代码确实有用,并且基于MSDN docs for Dispatcher.PushFrame解释如何执行相当于Application.DoEvents但来自WPF:

public void DoEvents()
{
    DispatcherFrame frame = new DispatcherFrame();
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
        new DispatcherOperationCallback(ExitFrames), frame);
    Dispatcher.PushFrame(frame);
}

public object ExitFrames(object f)
{
    ((DispatcherFrame)f).Continue = false;

    return null;
}

private void ButtonClick(object sender, RoutedEventArgs e)
{
    for (int i = 0; i < 500; i++)
    {
        label.Content = i.ToString();
        DoEvents();
    }
}

我仍然不建议这样做 - WPF(如Windows Forms)是基于事件驱动的工作方式设计的。

答案 1 :(得分:0)

处理程序正在占用事件循环。

一种选择是使用Application.DoEvents方法来允许执行绘制操作。 请注意,这被认为是不好的做法,因为Thread.Sleep将使UI无响应。

private void button1_Click(object sender, RoutedEventArgs e)
{
        int i = 0;

        while (i < 500)
        {
            label1.Content = i.ToString();
            System.Threading.Thread.Sleep(2000);
            Application.DoEvents();
            ++i;
        }
 }

另一个选择是对每个label1.Content = ..操作使用Control.BeginInvoke。

答案 2 :(得分:0)

像这样更新你的方法:

private void button1_Click(object sender, RoutedEventArgs e)
{
        int i = 0;

        while (i < 500)
        {
            label1.Content = i.ToString();
            //Update the UI
            Application.DoEvents();
        //  System.Threading.Thread.Sleep(2000);
            ++i;
        }
 }

这是最简单的方法。但不是首选的。首选的是使用backgroundworker来满足这种需求。

答案 3 :(得分:0)

“如果我们处理按钮的click事件处理程序内部的整个搜索,我们永远不会给UI线程处理其他事件的机会.UI将无法响应输入或处理消息。它永远不会重新粉刷,永远不会回应按钮点击。“ - Source

无论如何,你要做的是创建一个执行for循环的工作线程,并使用Dispatcher.BeginInvoke更新UI。

答案 4 :(得分:-1)

我认为你需要的是

Label.Update();