C# 委托 线程 窗体假死
基础理论
控件的线程安全检测
Control的Invoke和BeginInvoke
- Control.Invoke,Control.BeginInvoke和delegate.Invoke,delegate.BeginInvoke是不同的。
- Control.Invoke中的委托方法,执行在主线程,也就是我们的UI线程。而Control.BeginInvoke从命名上来看虽然具有异步调用的特征(Begin),但也仍然执行在UI线程。
- 如果在UI线程中直接调用Invoke和BeginInvoke,数据量偏大时,依然会造成UI的假死。
体验BeginInvoke

privatevoid btn_Start_Click(object sender, EventArgs e)
{
// 储存UI线程的标识符
int curThreadID = Thread.CurrentThread.ManagedThreadId; new Thread((ThreadStart)delegate()
{
PrintThreadLog(curThreadID);
})
.Start();
} privatevoid PrintThreadLog(int mainThreadID)
{
// 当前线程的标识符
// A代码块
int asyncThreadID = Thread.CurrentThread.ManagedThreadId; // 输出当前线程的扼要信息,及与UI线程的引用比对结果
// B代码块
label1.BeginInvoke((MethodInvoker)delegate()
{
// 执行BeginInvoke内的方法的线程标识符
int curThreadID = Thread.CurrentThread.ManagedThreadId; label1.Text =string.Format("Async Thread ID:{0},Current Thread ID:{1},Is UI Thread:{2}",
asyncThreadID, curThreadID, curThreadID.Equals(mainThreadID));
}); // 挂起当前线程3秒,模拟耗时操作
// C代码块
Thread.Sleep(3000);
}

Control.BeginInvoke的真正含义
所以,msdn对Control.BeginInvoke给出了这样的解释:在创建控件的基础句柄所在线程上异步执行指定委托。
Control.Invoke、BeginInvoke与Windows消息
publicobject Invoke(Delegate method, paramsobject[] args)
{
using (new MultithreadSafeCallScope())
{
returnthis.FindMarshalingControl().MarshaledInvoke(this, method, args, true);
}
}
[EditorBrowsable(EditorBrowsableState.Advanced)]
public IAsyncResult BeginInvoke(Delegate method, paramsobject[] args)
{
using (new MultithreadSafeCallScope())
{
return (IAsyncResult)this.FindMarshalingControl().MarshaledInvoke(this, method, args, false);
}
}
privateobject MarshaledInvoke(Control caller, Delegate method, object[] args, bool synchronous)
if (!synchronous)
{
return entry;
}
if (!entry.IsCompleted)
{
this.WaitForWaitHandle(entry.AsyncWaitHandle);
}
Application.DoEvents
解决方案
尝试”无假死”

privatereadonlyint Max_Item_Count =10000; privatevoid button1_Click(object sender, EventArgs e)
{
new Thread((ThreadStart)(delegate()
{
for (int i =0; i < Max_Item_Count; i++)
{
// 此处警惕值类型装箱造成的"性能陷阱"
listView1.Invoke((MethodInvoker)delegate()
{
listView1.Items.Add(new ListViewItem(newstring[]
{ i.ToString(), string.Format("This is No.{0} item", i.ToString()) }));
});
};
}))
.Start();
}

问题分析
最终方案
- 新建Windows组件DBListView.cs,让它继承自ListView。
- 在控件中添加如下代码:
public DBListView()
{
// 打开控件的双缓冲
SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
}
privatevoid button1_Click(object sender, EventArgs e)
{
new Thread((ThreadStart)(delegate()
{
for (int i =0; i < Max_Item_Count; i++)
{
// 此处警惕值类型装箱造成的"性能陷阱"
dbListView1.Invoke((MethodInvoker)delegate()
{
dbListView1.Items.Add(new ListViewItem(newstring[]
{ i.ToString(), string.Format("This is No.{0} item", i.ToString()) }));
});
};
}))
.Start();
}
C# 委托 线程 窗体假死的更多相关文章
- 谈.Net委托与线程——解决窗体假死
转自:http://www.cnblogs.com/smartls/archive/2011/04/08/2008981.html#2457370 引言 在之前的<创建无阻塞的异步调用> ...
- C# winform窗体假死
C# winform窗体假死 我们经常会遇到当执行一个比较大的函数时,窗体会出现假死的现象,给用户的体验不是很好,于是我们遇到了问题,那么就必须解决,我们该如何解决呢,首先在自己的脑里画个问号,接下 ...
- C# 解决窗体假死的状态
异步调用是CLR为开发者提供的一种重要的编程手段,它也是构建高性能.可伸缩应用程序的关键.在多核CPU越来越普及的今天,异步编程允许使用非常少的线程执行很多操作.我们通常使用异步完成许多计算型.IO型 ...
- C#避免WinForm窗体假死
WinForm窗体在使用过程中如果因为程序等待时间太久而导致窗体本身假死无法控制,会严重影响用户的体验,这种情况大多是UI线程被耗时长的代码操作占用所致,可以新开一个线程用来完成耗时长的操作,然后再将 ...
- WinForm多线程及委托防止界面假死
当有大量数据需要计算.显示在界面或者调用sleep函数时,容易导致界面卡死,可以采用多线程加委托的方法解决. using System; using System.Collections.Generi ...
- WinForm多线程+委托防止界面假死
当有大量数据需要计算.显示在界面或者调用sleep函数时,容易导致界面卡死,可以采用多线程加委托的方法解决 using System; using System.Collections.Generic ...
- c#解决窗体假死的一种方法
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_C ...
- C# Winform 窗体界面”假死”后台线程阻塞 解决办法–BeginInvoke
原文:C# Winform 窗体界面"假死"后台线程阻塞 解决办法–BeginInvoke 这个方法可以用在任何后台任务耗时较长,造成界面“假死”界面控件不更新的情况. 比如要要执 ...
- 千万别在UI线程上调用Control.Invoke和Control.BeginInvoke,因为这些是依然阻塞UI线程的,造成界面的假死
原文地址:https://www.cnblogs.com/wangchuang/archive/2013/02/20/2918858.html .c# Invoke和BeginInvoke 区别 Co ...
随机推荐
- SQL插入字段
//SQL插入字段 String dropTable="drop table if exists test;"; String columnGid ="alter tab ...
- 【bzoj1179】[Apio2009]Atm
*题目描述: *输入: 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来 ...
- 在 mac 系统上安装 python 的 MySQLdb 模块
在 mac 系统上安装 python 的 MySQLdb 模块 特别说明:本文主要参考了Mac系统怎么安装MySQLdb(MySQL-Python) 第 1 步:下载 MySQL-python-1.2 ...
- 关于【C++项目:无法解析的外部符号】
1,基本原因,[链接器]->[附加库目录]没有填写相关库的路径.或没有在[链接器]->[输入]->[附加依赖项]中填写相关库的名称 2,高级原因:如果不是1的原因,那就有可能是平台与 ...
- javascript中for循环和标签元素赋值问题总结
<!DOCTYPE html><html><body><p>点击下面的按钮,将代码块循环五次:</p><button onclick= ...
- VB6 Webbowser控件与JS交互,无边框和屏蔽右键菜单
1. 屏蔽右键菜单 在菜单中单击"工程"->"引用",在列表中找到"Microsoft HTML Object Library"打上 ...
- 阶段1 语言基础+高级_1-3-Java语言高级_1-常用API_1_第1节 Scanner类_5-练习二_键盘输入三个数字
思路分析: 获取前两个数字中的看最大值,有多重写法,这里先演示第一种.三元运算符的方式
- Numpy的补充(重要!!)
轴的概念 英文解释 https://www.sharpsightlabs.com/blog/numpy-axes-explained/ 汉化解释 https://www.jianshu.com/p/ ...
- 测开之路一百零八:bootstrap表格
引入bootstrap和jquery 普通表格 html自带的边框线 bootstrap表格属性 bootstrap表格 边框线 鼠标经过变色 压缩表格,减小密度 自适应屏幕 隔行突出(变色) 表格里 ...
- Python解决ModuleNotFoundError: No module named 'Queue'的问题
我们知道Python2和Python3两个版本之间,有些不兼容的地方,Python3中引入Queue会报出这个问题. Python3中要这样引入: import queue Python2中要这样引入 ...