`
jelly_bitores
  • 浏览: 46761 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

C#多线程与界面操作c# delegate(委托)与多线程窗体传值

    博客分类:
  • C#
 
阅读更多

c# delegate(委托)与多线程
很多时候写windows程序都需要结合多线程,在.net中用如下得代码来创建并启动一个新的线程。
public void ThreadProc();
Thread thread = new Thread( new ThreadStart( ThreadProc ) );
thread.IsBackground = true;
thread.Start();
但是很多时候,在新的线程中,我们需要与UI进行交互,在.net中不允许我们直接这样做。可以参考MSDN中的描述:
“Windows 窗体”使用单线程单元 (STA) 模型,因为“Windows 窗体”基于本机 Win32 窗口,而 Win32 窗口从本质上而言是单元线程。STA 模型意味着可以在任何线程上创建窗口,但窗口一旦创建后
就不能切换线程,并且对它的所有函数调用都必须在其创建线程上发生。除了 Windows 窗体之外,.NET Framework中的类使用自由线程模型。
STA 模型要求需从控件的非创建线程调用的控件上的任何方法必须被封送到(在其上执行)该控件的创建线程。基类 Control 为此目的提供了若干方法(Invoke、BeginInvoke 和 EndInvoke)。Invoke
生成同步方法调用;BeginInvoke 生成异步方法调用。
Windows 窗体中的控件被绑定到特定的线程,不具备线程安全性。因此,如果从另一个线程调用控件的方法,那么必须使用控件的一个 Invoke 方法来将调用封送到适当的线程。
正如所看到的,我们必须调用Invoke方法,而BeginInvoke可以认为是Invoke的异步版本。调用方法如下:
public delegate void OutDelegate(string text);
public void OutText(string text)
{
     txt.AppendText(text);
     txt.AppendText( "\t\n" );
}
OutDelegate outdelegate = new OutDelegate( OutText );
this.BeginInvoke(outdelegate, new object[]{text});
如果我们需要在另外一个线程里面对UI进行操作,我们需要一个类似OutText的函数,还需要一个该函数的委托delegate,当然,这里展示的是自定义的,.net中还有很多其他类型的委托,可以直接使用
,不需要而外声明。例如:MethodInvoker和EventHandler,这两种类型委托的函数外观是固定的,MethodInvoker是void Function()类型的委托,而EventHandler是void Function(object, EventArgs)
类型的委托,第一个不支持参数,第二中的参数类型和数量都是固定的,这两种委托可以很方便的调用,但是缺乏灵活性。请注意BeginInvoke前面的对象是this,也就是主线程。现在再介绍
Control.InvokeRequired,Control是所有控件的基类,对于这个属性MSDN的描述是:
获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程以外的线程中。
该属性可用于确定是否必须调用 Invoke 方法,当不知道什么线程拥有控件时这很有用。
也就是说通过判断InvokeRequired可以知道是否需要用委托来调用当前控件的一些方法,如此可以把OutText函数修改一下:
public delegate void OutDelegate(string text);
public void OutText(string text)
{
     if( txt.InvokeRequired )
     {
         OutDelegate outdelegate = new OutDelegate( OutText );
         this.BeginInvoke(outdelegate, new object[]{text});
         return;
     }
     txt.AppendText(text);
     txt.AppendText( "\t\n" );
}
注意,这里的函数没有返回,如果有返回,需要调用Invoke或者EndInvoke来获得返回的结果,不要因为包装而丢失了返回值。如果调用没有完成,Invoke和EndInvoke都将会引起阻塞。
现在如果我有一个线程函数如下:
public void ThreadProc()
{
     for(int i = 0; i < 5; i++)
     {
         OutText( i.ToString() );
         Thread.Sleep(1000);
     }
}
如果循环的次数很大,或者漏了Thread.Sleep(1000);,那么你的UI肯定会停止响应,想知道原因吗?看看BeginInvoke前面的对象,没错,就是this,也就是主线程,当你的主线程不停的调用OutText的
时候,UI当然会停止响应。
与以前VC中创建一个新的线程需要调用AfxBeginThread函数,该函数中第一个参数就是线程函数的地址,而第二个参数是一个类型为LPVOID的指针类型,这个参数将传递给线程函数。现在我们没有办法
再使用这种方法来传递参数了。我们需要将传递给线程的参数和线程函数包装成一个单独的类,然后在这个类的构造函数中初始化该线程所需的参数,然后再将该实例的线程函数传递给Thread类的构造
函数。代码大致如下:
public class ProcClass
{
     private string procParameter = "";
     public ProcClass(string parameter)
     {
         procParameter = parameter;
     }
     public void ThreadProc()
     {
     }
}
ProcClass threadProc = new ProcClass("use thread class");
Thread thread = new Thread( new ThreadStart( threadProc.ThreadProc ) );
thread.IsBackground = true;
thread.Start();
就是这样,需要建立一个中间类来传递线程所需的参数。
那么如果我的线程又需要参数,又需要和UI进行交互的时候该怎么办呢?可以修改一下代码:
public class ProcClass
{
     private string procParameter = "";
     private Form1.OutDelegate delg = null;
     public ProcClass(string parameter, Form1.OutDelegate delg)
     {
         procParameter = parameter;
         this.delg = delg;
     }
     public void ThreadProc()
     {
         delg.BeginInvoke("use ProcClass.ThreadProc()", null, null);
     }
}
ProcClass threadProc = new ProcClass("use thread class", new OutDelegate(OutText));
Thread thread = new Thread( new ThreadStart( threadProc.ThreadProc ) );
thread.IsBackground = true;
thread.Start();
分享到:
评论

相关推荐

    VB.Net-C#多线程Thread-代理委托delegate编程

    最近收集的VB.Net-C#多线程Thread-代理委托delegate编程。文章列表: c#.net多线程同步.txt C#WebBrowser页面与WinForm交互技巧一.txt C#多线程编程-多细全.txt C#多线程编程简单实例.txt C#多线程窗体控件安全访问....

    c# 委托访问listbox多线程操作

    ### C# 委托访问 ListBox 的多线程操作 #### 概述 在 C# 编程语言中,为了确保界面的响应性并避免在执行长时间运行的任务时导致用户界面(UI)冻结,通常会采用多线程技术来处理后台任务。在本案例中,介绍了一种...

    c# 窗体传值总结

    本文将对C#窗体传值的几种主要方法进行详细的总结,包括属性传值、构造函数传值、事件委托传值、直接传值、回传以及多窗体之间的传值策略。 1. **属性传值**: 在C#中,窗体对象通常包含多个属性,这些属性可以...

    C# winform 防止界面卡住 线程 委托

    在C# WinForm开发中,我们常常遇到这样一个问题:当执行耗时操作(如大量数据处理、网络请求等)时,界面会变得无响应,即“卡住”。为了解决这个问题,我们需要理解并运用线程和委托的概念。本文将详细阐述如何在C#...

    c#多线程中子线程动态改变ui控件

    C#多线程中子线程动态改变UI控件 在桌面应用程序中,控制UI界面是一个非常重要的任务。特别是在C#多线程编程中,子线程更新UI控件是一个常见的问题。本文将总结C#子线程更新UI控件的方法,介绍两种常用的方法,以便...

    C#多线程实现等待窗体

    在C#编程中,多线程技术是一种关键的优化手段,尤其在开发用户界面(UI)应用程序时。当程序需要执行耗时的操作,如大数据处理、网络请求或数据库操作,如果这些任务都在主线程上执行,那么UI将被阻塞,导致用户界面无...

    winform中可使用的委托事件,窗体之间可以传值

    - 在多线程环境下,需要确保在正确的线程上操作UI元素,通常需要使用`Control.Invoke`或`Control.BeginInvoke`方法。 通过以上步骤,我们可以在Winform的多个窗体之间建立数据通信,使得不同组件之间的协作变得...

    C#多线程操作

    ### C#多线程操作详解 #### 一、线程的概念与重要性 在计算机科学领域,线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。程序员可以通过多线程技术来实现并发执行任务,...

    C#跨窗体(Winform)调用控件(委托回调)

    当我们谈论“跨窗体”调用控件时,我们通常是指在一个窗体(Form)上操作的代码想要影响或与另一个窗体上的控件交互。在这个过程中,“委托”和“回调”扮演着关键的角色。本文将深入探讨这两个概念以及它们如何在C#...

    简单C#winform多线程委托调用进度条

    在C# WinForm应用开发中,多线程和进度条的使用是常见的需求,尤其是在执行耗时操作如文件上传、下载或大数据处理时,为了不阻塞用户界面(UI),我们通常会创建一个后台线程来执行这些任务,同时通过进度条实时反馈...

    C#窗体传值的方法总结

    在C#编程中,窗体间的传值是常见的操作,特别是在开发多窗口的应用程序时。下面将详细介绍几种在C#窗体之间传递数据的方法,并结合示例进行解析。 1. 所有权法: 这种方法是通过设置子窗体的所有者为主窗体,然后...

    委托:实现窗体间的传值

    在WinForms开发中,我们经常需要在多个窗体之间传递数据,以实现不同界面之间的交互。委托是C#中一个强大的特性,它可以作为方法的引用,允许我们在程序的不同部分之间传递行为。在这个场景下,我们将探讨如何使用...

    窗体之间实时传值

    这时,我们可以采用委托和事件的方式来实现窗体之间的实时传值。本文将详细解释这一方法及其优势,并给出具体实现步骤。 首先,理解委托的概念。委托在C#中相当于一个指向方法的指针,它可以存储对方法的引用,并...

    c#窗体传值方法总结

    在C#编程中,窗体间的传值是一个常见的需求,特别是在开发多窗口应用程序时。本文将深入探讨如何在C#窗体之间传递数据,主要涉及委托、属性、线程等方法。下面,我们将逐一详细解释这些方法。 1. **属性...

    C#多线程函数如何传参数和返回值[归类].pdf

    "C#多线程函数如何传参数和返回值" 在C#中,多线程函数的参数传递和返回值处理是非常重要的。多线程函数可以使用委托(delegates)来实现参数的传递和返回值的处理。 委托是具有同样参数和返回值的函数的集合。...

    C#多线程笔记

    ### C#多线程知识点详解 #### 一、线程与窗体间的交互 在C#编程中,每个窗体通常都运行在一个独立的线程上。这意味着如果一个应用程序包含多个窗体,那么这些窗体将分别运行在各自的线程之上。当需要实现不同窗体...

    C# 两个窗体之间实时传递数据的实例

    在C#编程中,开发GUI应用程序时经常需要在不同的窗体之间传递数据。在这个实例中,我们将探讨如何在两个窗体之间...通过学习和实践这个实例,你将更深入地理解C#中委托和事件的应用,以及在窗体间传递数据的最佳实践。

    c# 跨窗体操作 委托

    在跨窗体操作中,委托充当了一个桥梁,连接了发送数据或调用方法的源窗体与接收数据或执行方法的目标窗体。 **二、跨窗体操作的需求** 在多窗体应用中,我们可能需要从一个窗体(如主窗体)启动另一个窗体(如设置...

    c#编程跨线程调用窗体的方法

    ### C#编程中跨线程调用窗体的方法 在C#编程中,尤其是在涉及到图形用户界面(GUI)的应用程序开发时,经常会遇到需要在不同的线程之间进行数据交互或控制的情况。例如,在进行长时间的任务处理(如文件复制、网络...

    C# 多线程讲解的基础概念

    C# 多线程讲解的基础概念 多线程开发的基础知识点包括:创建线程、线程池、同步和异步、WinForm 多线程编程、线程安全、锁定机制等。 一、创建线程 创建线程有多种方式,包括使用 Thread 类、Delegate....

Global site tag (gtag.js) - Google Analytics