WPF中Timer与DispatcherTimer类的区别

利用一个计时器Timer类,实时更新界面上的控件内容,但是一直遇到抛出异常:System.InvalidOperationException {"调用线程无法访问此对象,因为另一个线程拥有该对象。"} 。

测试代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Timers;

namespace TimerTest
{
    /// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
    public partial class MainWindow : Window
    {
        private Timer aTimer = null;
        public MainWindow()
        {
            InitializeComponent();

            aTimer = new Timer();
            aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
            // Set the Interval to 5 seconds.
            aTimer.Interval = 1000;
            aTimer.Enabled = true;
            aTimer.Start();
        }

        private void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            timeLabel.Content = DateTime.Now.ToUniversalTime();
        }
    }
}

Debug的时候,发现在第38行的时候,timeLabel.Content 赋值的时候抛出了该异常

Google搜索了一下发现:”访问 Windows 窗体控件本质上不是线程安全的。如果有两个或多个线程操作某一控件的状态,则可能会迫使该控件进入一种不一致的状态。还可能出现其他与线程相关的 bug,包括争用情况和死锁。确保以线程安全方式访问控件非常重要。“——来自MSDN http://msdn.microsoft.com/zh-cn/library/ms171728(en-us,VS.80).aspx

哎,在群上回答说了一句:子线程无法访问界面线程的对象。被指没学过C#(的确,我学C#就是在一周之内看完一本几百页的书),这句话说的的确不够严谨,因为是有方法的,可以通过委托的方式进行访问,同时,这个界面线程的对象是指控件,如Label,TextBox之类。之前都写一个Qt程序的时候也遇到类似的问题,也是类似的情况:在子线程中试图直接更新界面上的一张图片,结果程序奔溃了,调试了很久才发现问题所在。

这时候我就想起来前阵子做过的一个练习,使用DispatcherTimer来实现更新。测试了一下,发现可行啊!!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Timers;
using System.Windows.Threading;

namespace TimerTest
{
    /// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
    public partial class MainWindow : Window
    {
        private DispatcherTimer dispatcherTimer = null;
        public MainWindow()
        {
            InitializeComponent();

            dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
            dispatcherTimer.Tick += new EventHandler(OnTimedEvent);
            dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
            dispatcherTimer.Start();
        }

        private void OnTimedEvent(object sender, EventArgs e)
        {
            timeLabel.Content = DateTime.Now.ToUniversalTime();
        }
    }
}

于是好奇这两者有什么不同?

仔细阅读MSDN上的文档后,可以得知:DispatcherTimer在界面线程中实现的,当然可以安全地访问,修改界面内容。

If a System.Timers.Timer is used in a WPF application, it is worth noting that the System.Timers.Timer runs on a different thread then the user interface (UI) thread. In order to access objects on the user interface (UI) thread, it is necessary to post the operation onto the Dispatcher of the user interface (UI) thread using Invoke or BeginInvoke. Reasons for using a DispatcherTimer opposed to a System.Timers.Timer are that theDispatcherTimer runs on the same thread as the Dispatcher and a DispatcherPriority can be set on the DispatcherTimer.

呵呵,区别就是在这里了!!
附:感谢群里高手的指点,采用Timer,使用Invoke或者BeginInvoke的方式进行UI的更新的方式(好处在于:在DispatcherTimer里面执行等待动作或者时间过长,可能会导致UI假死):

using System;
using System.Windows;
using System.Timers;
using System.Windows.Threading;

namespace TimerTest
{
    /// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
    public partial class MainWindow : Window
    {
        private Timer aTimer = null;

        private delegate void TimerDispatcherDelegate();

        public MainWindow()
        {
            InitializeComponent();

            aTimer = new Timer(1000);
            aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
            aTimer.Interval = 1000;
            aTimer.Enabled = true;
        }

        private void OnTimedEvent(object sender, EventArgs e)
        {
            this.Dispatcher.Invoke(DispatcherPriority.Normal,
                new TimerDispatcherDelegate(updateUI));
        }

        private void updateUI()
        {
            timeLabel.Content = DateTime.Now.ToUniversalTime();
        }
    }
}

时间: 2024-10-10 15:19:17

WPF中Timer与DispatcherTimer类的区别的相关文章

关于WPF中关于样式和模板的区别

百度了下,改天整理. WPF中关于样式和模板的区别: 回答一: 1.WPF样式类似于Web应用程序中的CSS,在WPF中可以为控件定义统一的样式(Style).样式属于资源的一种,例如为Button定义统一的背景颜色和字体: <Window.Resources> <Style  TargetType="Button"> <Setter Property="Background" Value="Yellow" />

WPF中timer的使用

Timer控件/ System.Timers.Timer 不能用于WPF中.在WPF中,定时器为 DispatcherTimer. 使用方法如下: private DispatcherTimer timer; public Window1(){    InitializeComponent();    Loaded += new RoutedEventHandler(Window1_Loaded);} void Window1_Loaded(object sender, RoutedEventA

C++中结构体和类的区别

在C++中,结构体是一种特殊形态的类. 结构体和类的唯一区别就是:  结构体和类具有不同的默认访问控制属性. 类中,对于未指定访问控制属性的成员,其访问控制属性为私有类型(private) 结构体中,对于未指定任何访问控制属性的成员,其访问控制属性为公有类型(public) C++中,不使用结构体丝毫不会影响程序的表达能力.C++之所以要引入结构体,是为了保持和C程序的兼容性. 但有时仍会在C++中使用结构体,是因为,可以使用结构体将不同类型数据组成整体,方便于保存数据.(若用类来保存,因类中成

WPF中使用定时器 DispatcherTimer 做TCP连接中的心跳 HeartBeat

开发过程中经常遇到定时触发的需求,如:TCP/IP连接中,使用心跳包保持连接或检测连接是否已经中断. WPF中有多种定时器: 1.using System.Windows.Threading; 代码如下: using System.Windows.Threading; public partial class MainWindow : Window { DispatcherTimer timerHeartBeat = new DispatcherTimer(); public MainWindo

C++中结构体与类的区别(struct与class的区别)

转载来源:http://blog.sina.com.cn/s/blog_48f587a80100k630.html C++中的struct对C中的struct进行了扩充,它已经不再只是一个包含不同数据类型的数据结构了,它已经获取了太多的功能. struct能包含成员函数吗? 能! struct能继承吗? 能!! struct能实现多态吗? 能!!! 既然这些它都能实现,那它和class还能有什么区别? 最本质的一个区别就是默认的访问控制: 默认的继承访问权限 struct是public的,cla

C++中结构体与类的区别

C++中的struct对C中的struct进行了扩充,它已经不再只是一个包含不同数据类型的数据结构了,它已经获取了太多的功能. struct能包含成员函数吗? 能! struct能继承吗? 能!! struct能实现多态吗? 能!!! 既然这些它都能实现,那它和class还能有什么区别? 最本质的一个区别就是默认的访问控制: 默认的继承访问权限:struct是public的,class是private的. 你可以写如下的代码: struct A {   char a; }: struct B :

wpf中textbox与textblock有什么区别

textbox是windows.form控件,textblock是WPF控件. 功能类似,但后者功能更强,也节省系统资源 wpf是基于directx技术的系统,向后兼容性更好. textblock只用来显示文本.

WPF中,Grid与Table的区别(英文)-转载

原文地址:http://blog.csdn.net/johnsuna/article/details/1742799 How is Grid Different from Table?Table and Grid share some common functionality, but each is best suited for different scenarios.(1)Grid derives from the Panel element, it defines a flexible

WPF中使用VisualBrush的实例

本文实现一个名为"你来我往"的小程序,该程序管理着"张三"和"李四"两位童鞋拥有的现金,一开始,两人均拥有100美元的现金,随着将现金从其中一人转移至另外一人,两人拥有的现金数在不断变化,程序可以跟踪这种变化,并正确显示每人拥有的现金数.每次最多可以转移三张纸币,纸币的金额可以是5美元.10美元或者20美元. 程序运行后的效果如图1所示,我们点击"张三"右边的"5美元""10美元"&qu