惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google Online Security Blog
Google Online Security Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
C
CERT Recently Published Vulnerability Notes
C
Cybersecurity and Infrastructure Security Agency CISA
Cisco Talos Blog
Cisco Talos Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
Scott Helme
Scott Helme
Project Zero
Project Zero
E
Exploit-DB.com RSS Feed
S
Secure Thoughts
K
Kaspersky official blog
L
Lohrmann on Cybersecurity
NISL@THU
NISL@THU
WordPress大学
WordPress大学
N
News and Events Feed by Topic
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LINUX DO - 热门话题
小众软件
小众软件
P
Privacy & Cybersecurity Law Blog
博客园 - 聂微东
Google DeepMind News
Google DeepMind News
H
Hackread – Cybersecurity News, Data Breaches, AI and More
A
About on SuperTechFans
Hacker News: Ask HN
Hacker News: Ask HN
AWS News Blog
AWS News Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
H
Hacker News: Front Page
F
Full Disclosure
Latest news
Latest news
Schneier on Security
Schneier on Security
The Hacker News
The Hacker News
T
Troy Hunt's Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Jina AI
Jina AI
Martin Fowler
Martin Fowler
P
Proofpoint News Feed
TaoSecurity Blog
TaoSecurity Blog
G
GRAHAM CLULEY
Forbes - Security
Forbes - Security
V
V2EX - 技术
酷 壳 – CoolShell
酷 壳 – CoolShell
V
Vulnerabilities – Threatpost
C
Cyber Attacks, Cyber Crime and Cyber Security
MongoDB | Blog
MongoDB | Blog
博客园 - 三生石上(FineUI控件)
S
SegmentFault 最新的问题
Hugging Face - Blog
Hugging Face - Blog
P
Privacy International News Feed
C
Check Point Blog
N
News and Events Feed by Topic

博客园 - 残香恨

WinForm:如何设置DataGridView列标题对齐方式 WinForm:如何在ListBox中添加CheckBox ASP.NET WebForm开发WAP网站 lock语句的递归问题 VS 2010 调试 .NET Framework 源代码 最近遇到的两个问题 ASP.NET MVC 2 模板化辅助方法 SQL Server 2008 Express 升级R2全过程 自定义ASP.NET MVC Html辅助方法 - 残香恨 将ASP.NET MVC 1.0升级到ASP.NET MVC 2的三种方法 .NET 4.0:一段动态绑定代码的底层初级分析 Visual Studio 2010 RTM版安装初体验 .NET中的线程 .NET 4.0 任务(Task) C#4.0 动态绑定(Dynamic Binding) .NET4.0新功能:任务(Task) .NET4.0线程池的Cooperative Cancellation模式 Visual Studio 2010 RC初体验 SQL Server导入文本文件时选择相同数据类型的一个小技巧
SynchronizationContext对Windows Forms窗体控件的更新方法
残香恨 · 2010-05-23 · via 博客园 - 残香恨

  众所周知,.NET Framework 支持几种不同类型的应用程序,而每种应用程序所支持的线程模型也不相同。Console、Windows Service应用程序不对线程做任何限制,即在这两种应用程序中,线程可做任何它想做的事;而Windows Forms(从.NET Framework 2.0开始)、WPF、Silverlight支持的线程模型是:窗体控件只允许创建它的线程可以对其进行更新。如果是非创建线程对其更新,在VS中调试时,则会抛出InvalidOperationException异常,并提示:从不是创建控件的线程访问它。虽然在非调试状态下不会抛出这个异常,但这样做不是线程安全的。

  在Windows Forms中,为了解决从非创建线程更新的问题,我们可以通过调用Form.CheckForIllegalCrossThreadCalls属性并将其值设为false,正如前面所说,这不是线程安全的,所以不建议这样做。于是MS为我们提供了一种新的更新方式:通过委托转到创建线程进行更新。比如,我们要在一个非创建线程里对窗体中的一个TextBox控件的Text属性进行更新,我们会写出大致如下的代码: 

代码

//声明一个委托,DoUpdateUI方法与其签名匹配
delegate void UpdateUIDelegate(TextBox tb, string result);
//更新方法,将更新操作从非创建线程转到创建线程,tb参数代表要更新的控件ID,result代表更新的文本信息
private void DoUpdateUI(TextBox tb, string result)
{
  if (tb.InvokeRequired)
  {
    UpdateUIDelegate d
= new UpdateUIDelegate(DoShowUI);
    this.Invoke(d, new object[] { tb, result });
  }
  else
  {
    tb.Text
= result;
  }
}

  如果要在非创建线程中对控件进行更新,我们只需调用DoUpdateUI方法,并传入相应参数即可。也许你可能觉得这样不方便,那好,这篇博客要讲的重点就是一种新的更新方法。

  在System.Threading命令空间下,有个SynchronizationContext类,我们可以通过SynchronizationContext.Current获得与当前应用程序类型对应的SynchronizationContext派生类的引用(Console程序类型会返回null)。SynchronizationContext类的定义大致如下代码所示:

代码

public class SynchronizationContext {
public static SynchronizationContext Current { get; }
public virtual void Post(SendOrPostCallback d, object state); // Call asynchronously
public virtual void Send(SendOrPostCallback d, object state); // Call synchronously
}

它有两个方法,Post和Send。在Windows Forms中,SynchronizationContext的派生类的Post方法会调用System.Windows.Forms.Control.BeginInvoke 方法,而Send方法则调用的是 System.Windows.Forms.Control.Invoke 方法,所以推荐使用Post方法,因为它是异步的,代表着更高的性能。

  下面的代码演示了利用SynchronizationContext类的派生类在非创建线程中更新窗体控件,你会觉得比起直接用委托更加简单些了。

代码

private void btnTest_Click(object sender, EventArgs e)
{
  //此处获取创建线程的SynchronizationContext类引用,并传给线程池线程
SynchronizationContext currentAsync
= SynchronizationContext.Current;
ThreadPool.QueueUserWorkItem(Execute, currentAsync);
}
private void Execute(object status)
{
SynchronizationContext currentAsync
= status as SynchronizationContext;
if (currentAsync != null)
{
   //在线程池中通过Post方法更新窗体控件
currentAsync.Post((obj)
=> { lbStatus.Text = obj.ToString(); }, "创建对象成功!");
}
}

  总结:由于Windows Forms、WPF、Silverlight应用程序类型的线程模型原因,同时,也为了线程同步安全性的考虑,我们对窗体控件的更新最好转到创建线程中去。本文演示了SynchronizationContext派生类在非创建线程中对Windows Forms窗体控件的更新,虽然本质上没有变化,但我觉得,在很多时候,比直接用委托方式更加简单。