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

推荐订阅源

博客园 - 叶小钗
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Security Blog
Microsoft Security Blog
罗磊的独立博客
大猫的无限游戏
大猫的无限游戏
美团技术团队
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
aimingoo的专栏
aimingoo的专栏
腾讯CDC
WordPress大学
WordPress大学
Apple Machine Learning Research
Apple Machine Learning Research
F
Fortinet All Blogs
G
Google Developers Blog
MongoDB | Blog
MongoDB | Blog
Microsoft Azure Blog
Microsoft Azure Blog
小众软件
小众软件
Engineering at Meta
Engineering at Meta
博客园_首页
B
Blog RSS Feed
D
Docker
M
MIT News - Artificial intelligence
爱范儿
爱范儿
I
InfoQ

博客园 - C#初学者009

脱壳学习 如何将字符串动态转换为指定的值类型 - C#初学者009 - 博客园 SQL Server表描述 及 字段描述的增、删、改、查询 关于Wind2003下MSDTC对DTS运行的影响 SQL 标识列起始种子重设 .net项目开发工具(V3.0 ) asp.net控件开发基础(5) -- 复杂属性、内嵌属性 - C#初学者009 如何用vb设置默认打印机? 如何使用 SetPrinter 修改打印机设置 用vb做的activex控件打包成cab后如何发布呢? VB中利用CopyMemory使用指针 如何用vb(API)代码设置不规则打印纸尺寸? 如何在 Windows NT 和 Windows 2000 中使用自定义页面大小打印(VB) 确定打印机状态和打印工作状态从Visual Basic VB怎么检测打印机状态 - C#初学者009 - 博客园 在.NET中实现对象序列化(转) XmlSerializer 常见问题疑难解答(MSDN) TransactionScope和分布式事务 (转) 对象序列化:使用System.Xml.Serialization命名空间(转)
C#跨线程操作控件 通过委托处理,MSDN上又很详细用法的说明 -...
C#初学者009 · 2009-06-14 · via 博客园 - C#初学者009

  问题     
        因为我的C#程序全是在VS2005上作的,以前学VB.NET的时候机器上是有VS2003的,现在没有2003了,所以我提出的问题不知道VS2003上有没有,看了不少关于线程操作的文章,都没有找到满意的答案.
           错误请看代码:

              private void change()
        {
            this.label1.Text = "已发生变化";
        }
private void button1_Click(object sender, EventArgs e) //按钮事件
        {
            Thread cha = new Thread(new ThreadStart(change));
            cha.Start();
        }

            错误提示:

           未处理 System.InvalidOperationException
Message="线程间操作无效: 从不是创建控件“label1”的线程访问它。"
Source="System.Windows.Forms"
StackTrace:
       在 System.Windows.Forms.Control.get_Handle()
       在 System.Windows.Forms.Control.set_WindowText(String value)
       在 System.Windows.Forms.Control.set_Text(String value)
       在 System.Windows.Forms.Label.set_Text(String value)
       在 进程控件.Form1.change() 位置 C:\Documents and Settings\win.LEGEND-ECDE46B9\My Documents\Visual Studio 2005\Projects\进程控件\进程控件\Form1.cs:行号 15
       在 System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       在 System.Threading.ThreadHelper.ThreadStart()
              无法跨线程操作,与创建控件的线程不一致
            解决方法:

private void change()
        {
            this.label1.Text = "已发生变化";
        }
private void threadchange()   //通过委托处理,MSDN上又很详细用法的说明
        {
            MethodInvoker In = new MethodInvoker(change);
            this.BeginInvoke(In);
        }
private void button1_Click(object sender, EventArgs e)
        {
            Thread cha = new Thread(new ThreadStart(threadchange));
            cha.Start();
        }

程序测试成功

C#2005后不再支持多线程直接访问界面的控件(界面创建线程与访问线程不是同一个线程),不过可以使用delegate来解决:

1. 声明一个delegate和定义一个delegate的实现函数
delegate void ShowProgressDelegate(int newPos);
private void ShowProgress(int newPos)
{
// 判断是否在线程中访问
if (!_progressBar.InvokeRequired)
{
// 不是的话直接操作控件
_progressBar.Value = newPos;
}
else
{
// 是的话启用delegate访问
ShowProgressDelegate showProgress = new ShowProgressDelegate(ShowProgress);
// 如使用Invoke会等到函数调用结束,而BeginInvoke不会等待直接往后走
this.BeginInvoke(showProgress, new object[] { newPos });
}
}

2. 定义线程函数(在另一个线程中可以对界面控件进读操作)
private void ProgressStart()
{
while (true)
{
int newPos = _progressBar.Value + 10;

if (newPos > _progressBar.Maximum)
{
newPos = _progressBar.Minimum;
}
Trace.WriteLine(string.Format("Pos: {0}", newPos));

// 这里直接调用方法,由其内部自动判断是否启用delegate
ShowProgress(newPos);
Thread.Sleep(100);
}
}

3. 线程的启动和终止
private Thread _progressThread;
_progressThread = new Thread(new ThreadStart(ProgressStart));
// 可选,功用:即使该线程不结束,进程也可以结束
_progressThread.IsBackground = true;
_progressThread.Start();

_progressThread.Abort();
// 可选,功用:等到线程结束才继续
_progressThread.Join();
_progressThread = null;