重要更新:
09.12.10.
System.Windows.Forms.Timer 在WPF 挂接的事件函数中被激活的时候不会运行,你可以设置它开始,并且状态也会是enabled = true, 但是就是不会计数
最安全还是要用 System.Timers.Timer
关键词 Key:
Exception Information: The calling thread cannot access this object because a different thread owns it.
Use timer in WPF.
原文链接 From:
http://daneshmandi.spaces.live.com/blog/cns!2DFAE0F19A7C2F5F!246.entry
我在项目中选择的解决方案 Solution I choosen:
Use System.Windows.Threading.DispatcherTimer replace timer
原文有其他的解决方案,请自行阅读
我的用法 How to use:
原文 Text:
{
public TimerTesting()
{
InitializeComponent();
System.Threading.TimerCallback tc = new System.Threading.TimerCallback(this.OnTimerCallback);
System.Threading.Timer objTimer = new System.Threading.Timer(tc);
objTimer.Change(0, 500);
}
private void OnTimerCallback(Object obj)
{
Random r = new Random();
this
.Background = new SolidColorBrush(Color.FromRgb((byte)(r.Next(0, 255)), (byte)(r.Next(0, 255)), (byte)(r.Next(0, 255))));}
}
When we wanted to set the background of the window in the Callback method this exception fires. "The calling thread cannot access this object because a different thread owns it.". This problem is due to UI thread in WPF is different from the thread that owns our timer. In fact, the Dispatcher object manage the UI (in this case the window). Therefore updating the UI should handle with Dispatcher object that owns it. So we should change our code in the CallBack method to this way:
private
void OnTimerCallback(Object obj){
this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
(System.Threading.ThreadStart)delegate()
{
Random r = new Random();
this.Background = new SolidColorBrush(Color.FromRgb((byte)(r.Next(0, 255)), (byte)(r.Next(0, 255)), (byte)(r.Next(0, 255))));
});
}
In WPF the only thread that created the DispatcherObject may access that object. Therefore we should first find the Dispatcher object of the window then tell it to update the data on the window. Moreover, The BeginInvoke method of the DispatcherObject executes the delegate asynchronously on the thread that the Dispatcher is associated with which in our code is the DispatcherObject of the window.
In the Case of Timer, we can use three kinds of Timers in WPF which two of them were available before WPF; As we dicussed above System.Threading.Timer and System.Timers.Timer. But the third one is made especially for WPF; System.Windows.Threading.DispatcherTimer. The difference between this timer with the two others is that it belongs to the same thread as WPF UI thread. By that I mean the DispatcherObject owns it. Better say, in the case of our example above the thread of the window and the timer are the same so we can Update the UI data without any problem.
public
partial class TimerTesting : Window{
public TimerTesting()
{
InitializeComponent();
System.Windows.Threading.DispatcherTimer dTimer = new System.Windows.Threading.DispatcherTimer();
dTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dTimer.Interval = TimeSpan.FromMilliseconds(500);
dTimer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
Random r = new Random();
this.Background = new SolidColorBrush(Color.FromRgb((byte)(r.Next(0, 255)), (byte)(r.Next(0, 255)), (byte)(r.Next(0, 255))));
}
}
You can download the complete source code here.