使用Control.Invoke处理多线程应用程序界面

程序|多线程

使用Control.Invoke处理多线程应用程序界面

使用单一线程,在进行大计算量或耗时的操作时,会使界面失去响应。Control.Invoke 提供了一个在工作线程中更新见面的简单办法。该函数会把作为参数的回调函数提交给应用程序的界面进程(一般是主线程)的队列中,等待处理。这样,对界面的操作便无须担心同步、互锁等问题。

以下例子摘自一个局域网资源搜索程序

       可以看到,线程池中的工作线程通过调用TreeView的Invoke方法,并提供一个回调函数,来实现对TreeView的更新。

       在Frameworks 1.1 中,部分简单的多线程更新界面并不需要这种操作,如修改一些静态文本框中的文本等。但在Frameworks 2.0,所有的操作都必须要以此方式完成。
private void SearchNet()

{
     //清除所有根节点下的字节点

     treeView1.Nodes[0].Nodes.Clear();

     for (uint i = IPStart; i <= IPEnd; i++)

     {

         //把整数转化IP地址,添加任务到线程池

         ThreadPool.QueueUserWorkItem(new WaitCallback(Search),

              ("\\\\" + (i >> 24).ToString() + '.' +

              (((int) i & 0x00ff0000) >> 16).ToString() + '.' +

              (((int) i & 0x0000ff00U) >> 8).ToString() + '.' + (i%256).ToString()));

     }

}

delegate void Updater(TreeNode Parent, TreeNode Child);
public void UpdateTreeView(TreeNode Parent, TreeNode Child)
{

     Parent.Nodes.Add(Child);
     treeView1.Nodes[0].Expand();
     foreach (TreeNode n in treeView1.Nodes[0].Nodes)

     {
         n.Expand();
     }

}
private void Search(object Host)

{

     WKSTA_INFO_100 stainfo;

     //尝试连接
     if(Connect(Host,out stainfo))

     {

         TreeNode nodecomputer = new TreeNode(stainfo.wki100_computername);

         //搜索共享
         SearchServer(nodecomputer,stainfo, (string)Host);
     }
}

private void SearchServer(TreeNode nodecomputer,WKSTA_INFO_100 stainfo, string Host)
{    

     /*其它代码*/

     treeView1.Invoke(new Updater(UpdateTreeView), new object[] {nodecomputer, node});

     /*其它代码*/

}

private void SearchNet()

{

     //清除所有根节点下的字节点
     treeView1.Nodes[0].Nodes.Clear();
     for (uint i = IPStart; i <= IPEnd; i++)
     {
         //把整数转化IP地址,添加任务到线程池
         ThreadPool.QueueUserWorkItem(new WaitCallback(Search),
              ("\\\\" + (i >> 24).ToString() + '.' +
              (((int) i & 0x00ff0000) >> 16).ToString() + '.' +
              (((int) i & 0x0000ff00U) >> 8).ToString() + '.' + (i%256).ToString()));
     }
}

delegate void Updater(TreeNode Parent, TreeNode Child);

public void UpdateTreeView(TreeNode Parent, TreeNode Child)

{

     Parent.Nodes.Add(Child);
     treeView1.Nodes[0].Expand();
     foreach (TreeNode n in treeView1.Nodes[0].Nodes)

     {
         n.Expand();
     }
}

private void Search(object Host)
{
     WKSTA_INFO_100 stainfo;
     //尝试连接

     if(Connect(Host,out stainfo))

     {
         TreeNode nodecomputer = new TreeNode(stainfo.wki100_computername);

         //搜索共享
         SearchServer(nodecomputer,stainfo, (string)Host);
     }

}

private void SearchServer(TreeNode nodecomputer,WKSTA_INFO_100 stainfo, string Host)

{    
     /*其它代码*/
     treeView1.Invoke(new Updater(UpdateTreeView), new object[] {nodecomputer, node});

     /*其它代码*/

}

private void SearchNet()
{

     //清除所有根节点下的字节点

     treeView1.Nodes[0].Nodes.Clear();

     for (uint i = IPStart; i <= IPEnd; i++)

     {
         //把整数转化IP地址,添加任务到线程池
         ThreadPool.QueueUserWorkItem(new WaitCallback(Search),

              ("\\\\" + (i >> 24).ToString() + '.' +
              (((int) i & 0x00ff0000) >> 16).ToString() + '.' +

              (((int) i & 0x0000ff00U) >> 8).ToString() + '.' + (i%256).ToString()));
     }
}

delegate void Updater(TreeNode Parent, TreeNode Child);
public void UpdateTreeView(TreeNode Parent, TreeNode Child)
{
     Parent.Nodes.Add(Child);
     treeView1.Nodes[0].Expand();
     foreach (TreeNode n in treeView1.Nodes[0].Nodes)
     {
         n.Expand();
     }

}

private void Search(object Host)
{
     WKSTA_INFO_100 stainfo;

     //尝试连接
     if(Connect(Host,out stainfo))
     {
         TreeNode nodecomputer = new TreeNode(stainfo.wki100_computername);

         //搜索共享
         SearchServer(nodecomputer,stainfo, (string)Host);

     }
}

private void SearchServer(TreeNode nodecomputer,WKSTA_INFO_100 stainfo, string Host)

{    
     /*其它代码*/

     treeView1.Invoke(new Updater(UpdateTreeView), new object[] {nodecomputer, node});

     /*其它代码*/
}

       总结如下:

1、  定义委托

2、  定义回调函数

3、  调用Control.Invoke()

个人感觉语法较麻烦,尤其是对每种界面修改都必须定义一种委托(因为参数不同),有办法改进么?

时间: 2024-08-03 06:52:07

使用Control.Invoke处理多线程应用程序界面的相关文章

C# WinForm多线程开发(三) Control.Invoke

原文地址:点击打开链接 [摘要]本文介绍C# WinForm多线程开发之Control.Invoke,并提供详细的示例代码供参考. 下面我们就把在Windows Form软件中使用Invoke时的多线程要注意的问题给大家做一个介绍. 首先,什么样的操作需要考虑使用多线程?总的一条就是,负责与用户交互的线程(以下简称为UI线程)应该保持顺畅,当UI线程调用的API可能引起阻塞时间超过30毫秒时(比如访问CD-ROM等速度超慢的外设.进行远程调用等等)就应该考虑使用多线程.为什么是30毫秒?30毫秒

阻塞-vb.net多线程造成窗体界面“假死”解决办法?

问题描述 vb.net多线程造成窗体界面"假死"解决办法? 我在一个窗体按钮单击事件里开了一个新线程用于连接一硬件设备,结果线程一start窗体就卡死了,造成窗体线程阻塞,我想知道时间片是如何分配的,默认优先级相同,为什新线程会独占时间片? 解决方案 我在编写MFC窗体程序时也测验过线程独占的情形,我猜想最可能的原因是:线程的开辟与管辖范围与主线程相干.

程序启动后,不在最前面显示,任务栏也没有,只有关掉前面窗口,才能看到程序界面,这时任务栏才有。

问题描述 我用了多线程技术用于下载和显示众多的图片.但当我启动程序时,程序在前面闪一下,然后躲到后面,不在最前面显示,任务栏也没有.只有关掉前面窗口,才能看到程序界面,这时任务栏才有.请高手指教. 解决方案 解决方案二:啥叫多线程技术啊?!你用什么,我不知道.

.NET程序界面探讨之1:Skin++篇

工作一直很忙,很久没有写博客了,有个朋友看过我的代码生成工具,觉得界面不错,随整理了一下界面代码,并加入了皮肤功能,现公布以飨读者.可能做过Winform界面的朋友都知道,能够实现换肤的控件有很多,但做的比较不错的有如ActiveSkin.SkinCrafter.Irisskin.Skin++等等,不过都是收费的界面控件,这些控件很多来自C++的时代,但由于是OCX控件的方式,所以也可以使用到C#的Winform界面换肤中.本人做过ActiveSkin.Skin++的界面换肤功能,觉得两者很是相

ASP程序界面的多语言支持

程序 ASP程序界面的多语言支持 可能有的web应用程序,需要多语言支持,例如,讨论组,既有中文界面,以适合国人使用的方便,又需要英文界面,以满足国际化的需要.我想,似乎没有必要为每一个语言都写一个版本,这不仅比较繁琐,而且以后程序升级就必须修改所有版本的程序.熟悉vc++程序的朋友一定知道通常windows应用程序的国际化手段都是通过rc文件来解决的.只要重新加入不同语言版本的rc文件编译一下就行了.asp程序不能编译也不需编译.我于是开始考虑使用数据库,将ASP程序中使用到的提示信息/甚至图

在C#中编写多线程应用程序,简单!

程序|多线程 (欢迎访问www.kunwsoft.com) 以前在使用VB来实现多线程的时候,发现有一定的难度.虽然也有这样那样的方法,但都不尽人意,但在C#中,要编写多线程应用程序却相当的简单.这篇文章将作简要的介绍,以起到抛砖引玉的作用! .NET将关于多线程的功能定义在System.Threading名字空间中.因此,要使用多线程,必须先声明引用此名字空间(using System.Threading;). 即使你没有编写多线程应用程序的经验,也可能听说过"启动线程""

程序界面多模式显示的实现

如果你用过RealPlayer播放器的话,那就一定对它的多模式显示方式不会陌生吧!RealPlayer拥有正常和精简两种显示模式.我们有时也想在自己的程序界面上实现类似的功能,该怎样实现呢?下面拿我用VC6.0做的一个多模式显示程序示例来向大家展示,它是怎样实现类似功能的.如下图所示:(图一) 正常显示模式:(图二)简洁显示模式,无视图:(图三),精简显示模式,仅工具条. 图一 图二 图三 基本构成思想: 实现原理很简单,只要分别获取窗体大小.客户区大小.工具条大小.状态条大小.边框大小以及标题

VC程序界面多模式显示

看过徐景周写过的一篇"程序界面多模式显示的实现",在一个应用程序中使程序拥有多种显示模式,但是这个界面是由SDI的MFC文档视图结构实现,但是使用的代码在MDI的多文档/视图中不能实现,通过MSDN我找到了一些实现 MDI 的多模式实现方法,不敢独享,与大家分享 . 利用SDI和MDI实现这种多模式的显示的应用程序,第一步首先要实现的是可以动态加载和销毁菜单.对于SDI的应用程序,实现是比较简单的,对于MDI的应用程序,实现则是有些麻烦,不过,这些都是可以做到的!呵,呵! 首先,要将S

多线程蜘蛛程序的实现

多线程蜘蛛程序是一个很有用的组件, 我在自己开发的Spider Studio中也提供了一个. 在设计上我尽量遵循使用简 单的原则, 大量使用dynamic对象的特性, 使得代码非常精简灵活, 通过17行就能实现一个功能比较齐全的蜘蛛程序. 现 在和大家分享一下: public void Run() { dynamic link = new ExpandoObject(); link.Url = "http://news.163.com"; Spider.AddLink(link); S