4

我一直在寻找一个原因,但是关于 stackoverflow 上的每一个主题,我都能找到一个繁忙的 UI 作为原因。我有非常基本的代码,仅用于测试,它根本不会更新 UI,即使我确信它不能忙于做其他事情:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    static double t = 0;
    static double dt = 0.1;

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        Timer timer = new Timer(5000);
        timer.Enabled = true;
        timer.Elapsed += new ElapsedEventHandler(Update);
        timer.Start();
    }

    void Update(object sender, ElapsedEventArgs e)
    {
        t = t + dt;
        testBlock1.Text = (t).ToString();
    }
}

我对其进行了调试并为textBlock1.Text更新设置了一个断点,它确实每 5 秒中断一次,但 UI 从未更新。从代码中可以看出,当我将鼠标移到Button用于启动计时器的按钮上时,按钮会显示其典型的“鼠标悬停”动画。为什么会发生这种情况,而不是文本更新?

如果有人可以引导我找到关于 stackoverflow 的一个好主题,请这样做,我将在这里删除我的问题,但我找不到任何主题来解释为什么即使 UI 不忙于做任何事情,这种方法也不会更新 UI别的。

4

2 回答 2

12

System.Timers.Timer默认情况下不会封送回 UI 线程。在 Windows 窗体中,您可以很容易地做到这一点:

Timer timer = new Timer(5000);
timer.SynchronizingObject = this;

...但是 WPF UI 元素不实现ISynchronizeInvoke,这将阻止它在 WPF 中为您工作。

您可以使用Dispatcher来编组到处理程序中的 UI 线程,或者您可以只使用 aDispatcherTimer开始。

于 2012-10-24T14:00:36.130 回答
8

对于 WPF,您应该使用DispatcherTimer- 同样使用您发布的上述代码,我收到一个cross thread错误,因为elapsed事件是在其他线程上引发的,而不是在UI thread.

private void button1_Click(object sender, RoutedEventArgs e)
{
   DispatcherTimer timer = new DispatcherTimer();
   timer.Interval = new TimeSpan(0, 0, 5);
   timer.Tick += new EventHandler(timer_Tick);
   timer.Start();
}

void timer_Tick(object sender, EventArgs e)
{
   t = t + dt;
   txt.Text = (t + dt).ToString();
}

编辑

此外,您可以使用现有代码在 UI Dispatcher 上编组它,如下所示 -

void Update(object sender, ElapsedEventArgs e)
{
    App.Current.Dispatcher.Invoke((Action)delegate()
    {
        t = t + dt;
        txt.Text = (t + dt).ToString();
    });
}
于 2012-10-24T14:07:03.387 回答