<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-3705274515307455421</id><updated>2009-02-20T18:31:01.126-08:00</updated><title type='text'>Gone with wind</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://tyraeltong.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705274515307455421/posts/default'/><link rel='alternate' type='text/html' href='http://tyraeltong.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>自有天逸</name><uri>http://www.blogger.com/profile/07080657973269089903</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>2</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3705274515307455421.post-2771868251252881853</id><published>2006-12-26T00:09:00.001-08:00</published><updated>2006-12-26T00:39:26.426-08:00</updated><title type='text'>WinForm和WPF中在工作者线程里更新UI对象</title><content type='html'>&lt;p&gt;这应该是每一个做客户端编程的人都曾经遇到过的问题：进行一个耗时较长的运算，并且在运算完成后需要更新UI对象的状态。一般来说这种运算（或者调用）我们会放在一个工作者线程中进行，完成了运算（或调用）之后，再根据运算结果通过一定的机制更新UI对象的状态。在WinForm开发中是通过Invoke方法来完成的。Invoke是在System.Windows.Forms.Control里面实现的，由于这个Control是WinForm所有UI元素类的基类，所以所有的WinForm UI对象都可以提供Invoke调用来实现从工作者线程到UI线程的切换。但是Invoke需要一个delegate参数，下面是一个简单的示例代码：&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;p style="COLOR: rgb(51,0,153);font-family:verdana;" &gt;&lt;span style="font-size:85%;"&gt;// This method is run on a worker thread&lt;br /&gt;private void DoWork()&lt;br /&gt;{&lt;br /&gt;...&lt;br /&gt;// Do Some works&lt;br /&gt;&lt;strong&gt;this.Invoke((MethodInvoker)delegate(){ UpdateUI();});&lt;br /&gt;&lt;/strong&gt;}&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="COLOR: rgb(51,0,153);font-size:85%;" &gt;&lt;span style="font-family:verdana;"&gt;// This method will update ui element&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;private void UpdateUI()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;这里我们甚至可以进一步改进UpdateUI方法，使其可以适应在UI线程内部被调用和被工作者线程中调用的两种不同情况，这是通过System.Windows.Forms.Control.InvokeRequired来实现的：&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;p style="COLOR: rgb(51,0,153)"&gt;// This method is run on a worker thread&lt;br /&gt;private void DoWork()&lt;br /&gt;{&lt;br /&gt;...&lt;br /&gt;// Do Some works&lt;br /&gt;UpdateUI();&lt;br /&gt;}&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="COLOR: rgb(51,0,153)"&gt;// This method will update ui element&lt;/span&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(51,0,153)"&gt;private void UpdateUI()&lt;/span&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(51,0,153)"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;strong style="COLOR: rgb(51,0,153)"&gt;if (InvokeRequired)&lt;br /&gt;{&lt;br /&gt;Invoke((MethodInvoker)delegate(){UpdateUI();});&lt;br /&gt;}&lt;/strong&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(51,0,153)"&gt;else&lt;/span&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(51,0,153)"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(51,0,153)"&gt;// Real update code&lt;/span&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(51,0,153)"&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(51,0,153)"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(51,0,153)"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;在.NET Framework2.0里，提供了一个新的类：BackgroundWorker，更简单的实现了工作者线程完成后更新UI对象的问题。BackgroundWorker提供了DoWork和RunWorkerCompleted这两个event供开发者挂接自己的delegate方法（当然还有其他event，但是先让我们只关注这两个）。DoWork挂接的delegate将会在.NET Thread Pool上面执行，而RunWorkerCompleted挂接的delegate将会在创建BackgroundWorker的线程上执行，一般来说也就是UI线程，所以我们可以在RunWorkerCompleted挂接的delegate里面自由的修改UI元素的状态而不用担心出现什么问题。BackgroundWorker还有其他一些方便的功能例如中途取消操作，操作进度报告等等，这里就不详细描述了。&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;在WPF里，所有的UI元素类都是重新实现的，机制与WinForm大不相同，也不从System.Windows.Forms.Control派生，所以也没有Invoke方法。那么在WPF里面应该怎么样处理工作者线程到UI线程的切换呢?这里需要使用Dispatcher。我们首先来看一下WPF里面UI对象的继承体系：&lt;br /&gt;&lt;img style="DISPLAY: block; MARGIN: 0px auto 20px; WIDTH: 417px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://farm1.static.flickr.com/57/330817329_a55b28e82a.jpg" border="0" /&gt;Dispathcer这个Property就是在DispatcherObject里面引入的。WPF里面的UI控件要嘛就是从图中的Control派生的，要嘛就是从FrameworkElement派生的，所以都包含了Dispatcher这个Property。使用的时候跟WinForm里面是很类似的：&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="COLOR: rgb(51,0,153)"&gt;void DoWork()&lt;/span&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(51,0,153)"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(51,0,153)"&gt;// do work&lt;/span&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(51,0,153)"&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(51,0,153)"&gt;// call dispatcher to update ui&lt;/span&gt;&lt;br /&gt;&lt;strong style="COLOR: rgb(51,0,153)"&gt;Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (System.Windows.Forms.MethodInvoker)delegate() { UpdateUI(); });&lt;br /&gt;&lt;/strong&gt;&lt;span style="COLOR: rgb(51,0,153)"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;不过Dispatcher有一个问题，它不像WinForm里面，有一个InvokeRequired Property指示是否需要进行线程切换，所以在这里就不管是否是在UI线程内部进行的调用，都会进行一次线程切换了。&lt;br /&gt;&lt;br /&gt;&lt;p class="zoundry_bw_tags"&gt;&lt;br /&gt;&lt;!-- Tag links generated by Zoundry Blog Writer. Do not manually edit. http://www.zoundry.com --&gt;&lt;br /&gt;&lt;span class="ztags"&gt;&lt;span class="ztagspace"&gt;Technorati&lt;/span&gt; : &lt;a class="ztag" href="http://technorati.com/tag/WPF%20WinForm%20UI%20Programming" rel="tag"&gt;WPF WinForm UI Programming&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3705274515307455421-2771868251252881853?l=tyraeltong.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tyraeltong.blogspot.com/feeds/2771868251252881853/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=3705274515307455421&amp;postID=2771868251252881853' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705274515307455421/posts/default/2771868251252881853'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705274515307455421/posts/default/2771868251252881853'/><link rel='alternate' type='text/html' href='http://tyraeltong.blogspot.com/2006/12/winformwpfui.html' title='WinForm和WPF中在工作者线程里更新UI对象'/><author><name>自有天逸</name><uri>http://www.blogger.com/profile/07080657973269089903</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02490427441178188540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705274515307455421.post-4127763652925136877</id><published>2006-12-26T00:06:00.000-08:00</published><updated>2006-12-26T00:09:27.945-08:00</updated><title type='text'>System.Windows.Forms.Timer和System.Timers.Timer的区别</title><content type='html'>&lt;p&gt;.NET Framework里面提供了三种Timer：&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;System.Windows.Forms.Timer&lt;/li&gt;&lt;br /&gt;&lt;li&gt;System.Timers.Timer&lt;/li&gt;&lt;br /&gt;&lt;li&gt;System.Threading.Timer&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;在我的记忆中，Visual Studio 2003的工具箱里面默认提供了System.Windows.Forms.Timer和System.Timers.Timer两种，而Visual Studio 2005中确只默认提供了System.Windows.Forms.Timer这一种。这里简单的介绍一下这两种Timer的区别。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;System.Windows.Forms.Timer是使用得比较多的Timer，Timer Start之后定时（按设定的Interval）调用挂接在Tick事件上的EvnetHandler。在这种Timer的EventHandler中可以直接获取和修改UI元素而不会出现问题--因为这种Timer实际上就是在UI线程自身上进行调用的。也正是因为这个原因，导致了在Timer的EventHandler里面进行长时间的阻塞调用，将会阻塞界面响应的后果。下面是一个简单的例子：&lt;br /&gt;&lt;/p&gt;&lt;blockquote style="COLOR: rgb(0,0,128)"&gt;&lt;p  style="font-family:verdana;"&gt;&lt;span style="font-size:85%;"&gt;public class MainForm : Form&lt;br /&gt;{&lt;br /&gt;private void MainForm_Load(object sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;timer.Interval = 1000;&lt;br /&gt;timer.Tick += delegate(object o, EventArgs args)&lt;br /&gt;{&lt;br /&gt;DoWork();&lt;br /&gt;};&lt;br /&gt;timer.Start();&lt;br /&gt;}&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Tahoma,sans-serif;font-size:85%;"&gt;private void DoWork()&lt;br /&gt;{&lt;br /&gt;for (int i = 0; i &amp;lt; 10; i++)&lt;br /&gt;{&lt;br /&gt;System.Threading.Thread.Sleep(1000);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;在这个例子中，DoWork方法里面将会阻塞10秒，在这10秒之内，UI将会失去响应。而通过使用System.Timers.Timer，就可以解决这个问题。因为System.Timers.Timer是在.NET的Thread Pool上面运行的，而不是直接在UI Thread上面运行，所以在这种Timer的EventHandler里面进行耗时较长的计算不会导致UI失去响应。但是这里有两个地方需要注意：&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;因为一般来说System.Timers.Timer不是运行在UI Thread上面的，所以如果要在这种Timer的EventHandler里面更新UI元素的话，需要进行一次线程切换，在WinForm开发中一般通过UI元素的Invoke方法完成：&lt;br /&gt;&lt;blockquote style="COLOR: rgb(0,0,128);font-family:Tahoma,sans-serif;font-size:0.9em;"  &gt;&lt;p  style="font-family:verdana;"&gt;&lt;span style="font-size:85%;"&gt;private void DoWork()&lt;br /&gt;{&lt;br /&gt;for (int i = 0; i &amp;lt; 10; i++)&lt;br /&gt;{&lt;br /&gt;System.Threading.Thread.Sleep(1000);&lt;br /&gt;}&lt;br /&gt;this.Invoke(new UpdateUICallBack(UpdateUI));&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p  style="font-family:verdana;"&gt;&lt;span style="font-size:85%;"&gt;private delegate void UpdateUICallBack();&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;private void UpdateUI()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;System.Timers.Timer有一个Property：&lt;strong&gt;SynchronizingObject&lt;/strong&gt; 。如果设置了这个Property（一般是某个Form），那么之后对Timer挂接的EventHandler的调用将会在创建这个UI元素的线程上进行（一般来说就是UI线程）。值得注意的是，如果你通过WinForm设计器把System.Timers.Timer拖放到Form上，那么这个Property将会自动被设置。此时这种Timer就和System.Windows.Forms.Timer的效果一样：长调用将会阻塞界面。&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;p class="zoundry_bw_tags"&gt;&lt;br /&gt;&lt;!-- Tag links generated by Zoundry Blog Writer. Do not manually edit. http://www.zoundry.com --&gt;&lt;br /&gt;&lt;span class="ztags"&gt;&lt;span class="ztagspace"&gt;Technorati&lt;/span&gt; : &lt;a class="ztag" href="http://technorati.com/tag/.NET%20Timer%20UI%20Programming" rel="tag"&gt;.NET Timer UI Programming&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3705274515307455421-4127763652925136877?l=tyraeltong.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tyraeltong.blogspot.com/feeds/4127763652925136877/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=3705274515307455421&amp;postID=4127763652925136877' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705274515307455421/posts/default/4127763652925136877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705274515307455421/posts/default/4127763652925136877'/><link rel='alternate' type='text/html' href='http://tyraeltong.blogspot.com/2006/12/systemwindowsformstimersystemtimerstime.html' title='System.Windows.Forms.Timer和System.Timers.Timer的区别'/><author><name>自有天逸</name><uri>http://www.blogger.com/profile/07080657973269089903</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02490427441178188540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry></feed>