首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >更新MainWindow上的Timer.Elapsed事件

更新MainWindow上的Timer.Elapsed事件
EN

Stack Overflow用户
提问于 2012-04-22 12:32:42
回答 3查看 3.6K关注 0票数 2

我正在编写一个家庭WPF应用程序,它在配置的间隔内从服务器获得一个文件。

这是一个基本的窗口,有几个标签。我有以下几点

  • 启动时间(反映DateTime“开始”事件被击中
  • 持续时间(反映应用程序运行的时间)
  • 速度(文件的下载速度)

我希望每秒钟更新主窗口的持续时间,因此我有下面的代码来完成此操作(在单独的类“RunDownloader.cs”中)。

代码语言:javascript
复制
    private void StartTickTimer()
    {
        const double interval = 1000;

        if (_tickTimer == null)
        {
            _tickTimer = new Timer
            {
                Interval = interval
            };
            _tickTimer.Elapsed += _ticktimer_Elapsed;
        }

        _tickTimer.Start();
    }

在_ticktimer_Elapsed上,我在主窗口_mainWindow.UpdateTicker()中调用一个方法;

这做了以下工作。

代码语言:javascript
复制
    public void UpdateTicker()
    {
        var timeStarted = lblTimeStarted.Content.ToString();
        DateTime startTime = DateTime.Parse(timeStarted);
        TimeSpan span = DateTime.Now.Subtract(startTime);

        //ToDo: Output time taken here!
        //lblTimeElapsed.Content =
    }

我有两个问题。

  1. 在调用lblTimeStarted.Content.ToString()时,我有以下异常:在UpdateTicker()中 “调用线程无法访问此对象,因为其他线程拥有该对象。”
  2. 我不太知道,如何正确显示来自TimeSpan的TimeSpan的持续时间

事先谢谢你的回答。:D

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-04-22 12:45:06

在WPF中,不能从UI线程以外的线程更新UI对象(这些对象是在UI线程上创建的)。

为了从其他线程(例如计时器线程)更新UI控件,您需要使用Dispatcher在UI线程上运行更新代码。

这个问题/回答可能会帮助你,或者你会通过搜索"WPF调度器“找到大量信息。

一个示例dispatcher调用-- lamda代码将被发送到UI线程上运行:

代码语言:javascript
复制
Dispatcher.BeginInvoke(new Action(() =>
{
    text_box.AppendText(formated_msg);
    text_box.ScrollToEnd();
}));

或者,您可以用DispatchTimer替换现有的计时器--与您正在使用的计时器不同,它确保计时器回调位于UI线程上:

使用DispatcherTimer而不是System.Timers.Timer的原因是,DispatcherTimer运行在与Dispatcher和DispatcherPriority相同的线程上,可以在DispatcherTimer上设置。

票数 6
EN

Stack Overflow用户

发布于 2012-04-22 12:56:07

  1. 您的计时器运行在自己的线程上,并从那里调用UpdateTicker()方法。但是,大多数UI框架,包括WPF,都禁止从创建相应控件的线程以外的线程访问UI控件(后者通常被称为"UI线程“)。在这里,您有两个主要选择:
代码语言:javascript
复制
- Use a `DispatcherTimer`. This will run on your UI thread and avoids any threading issues, but then, since your `UpdateTicker()` code also runs on this thread, your UI will be unresponsive while you are doing processing. This may or may not be an issue; if all you do is a couple of field/property changes, this is fine.
- In your timer callback, use `this.Dispatcher.Invoke()` or `this.Dispatcher.BeginInvoke()` to call your UI update method once other processing is completed (example: `this.Dispatcher.Invoke((Action) UpdateTicker)`). This will "bump" the call to the proper thread for the UI update, while maintaining the asynchrony for data processing. In other words, this is a more effective approach.

  1. TimeSpan结构有一个接受格式设置的ToString()方法;或者,如果不方便,它有几个助手属性(DaysHoursMinutesTotalDaysTotalHoursTotalMinutes等)。可以用于显示目的。
票数 1
EN

Stack Overflow用户

发布于 2012-04-22 13:07:19

您可以这样做:在主窗口中:

代码语言:javascript
复制
public void ChangeTime(string time)
        {
            lblsb.Content = time;
        }

在RunDownloader中:

代码语言:javascript
复制
class RunDownloader
    {
        Timer _tickTimer;
        MainWindow window;

        public RunDownloader(MainWindow window)
        {
            this.window = window;
        }

        private delegate void MyDel(string str);

        public void StartTickTimer()
        {
            const double interval = 1000;

            if (_tickTimer == null)
            {
                _tickTimer = new Timer
                {
                    Interval = interval
                };
                _tickTimer.Elapsed += (object sender, ElapsedEventArgs e) =>
                    {
                        window.Dispatcher.BeginInvoke(new MyDel(window.ChangeTime), DateTime.Now.ToLongDateString());
                    };
            }

            _tickTimer.Start();
        }

    }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10267956

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档