C#委托、操作主线程控件编程解读

1 委托简介

        C#允许用delegate关键字创建一种特殊的类,称为委托类。委托类的示例称为委托对象。

        委托对象是一种指向一个或者多个方法(静态或者非静态的引用)。我们可以用调研方法的语法“调用”委托对象。这样调用委托对象所引用的方法。如果这些方法的调用是在调用委托的方法所在线程中完成,这种调用成为同步调用。

1.1 委托建立和引用

(1)先定义一个方法,例如:

int Max(int x,int y){

return x>y?x:y;

}

(2)建立一个委托类型myDelegate,并声明该委托可以指向的方法的签名(函数原型) 

delegate void MyDelegate(int a,int b);

(3)建立一个委托类的实例md,并指向要调用的方法Max

//方法1:利用委托类的构造方法指定,这是最为常见的一种方式

 MyDelegate md=new MyDelegate(Max);

 //方法2:利用自动推断方式来指明要调用的方法,该形式更类型于函数指针

 MyDelegate md=Max;

1.2 利用委托类实例调用所指向的方法 

int c=md(4,5);

访问主线程控件

        C#中,跨线程访问控件必须要借用委托完成。跨线程对UI控件进行操作是比较常见的一种操作。例如图1,在主进程form1中,点击“启动线程”后开启一个子进程,在子进程将右下直角textbox的内容周期性的添加到上面的listbox中。

 图1 跨线程对UI控件进行操作

设计思路如下:(1)在Form1类中设置一个AddText(string text),负责将text添加到控件ltbViewText内容中,(2)如果是本线程调用AddText(),则直接对控件进行添加操作:ltbViewText.Items.Add(text),(3)如果是其他线程调用AddText(),必须必须通过控件的Invoke() 方法调用引用AddText的委托实例。

        判断是否是本线程操作控件的方法是根据控件的InvokeRequired属性值来决定:如果该值为true则是外部线程操作,否则就是本线程操作。

        AddText(string text)的实现代码如下:

        private delegate void AddTextDelegate(string text);//声明一个委托类

        public void AddText(string text){

            if (ltbViewText.InvokeRequired) //不是创建控件的线程操作,则通过调用委托完成

            {

                AddTextDelegate td = AddText; //创建一个委托类实例md->AddText

                ltbViewText.Invoke(td, text);//通过Invoke方法调用引用AddText的委托实例

            }

            Else //是,直接对控件进行操作——添加内容

                ltbViewText.Items.Add(text);

        }

实现对UI控件进行操作的主要流程图如下:

 图2 跨线程对UI控件进行操作的主要流程图

实现代码(代码来源于文献【1】)如下:

 (1)CTextOutput类,用于创建子线程

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace AccessControlInThread
{
    class CTextOutput
    {
        public volatile bool shouldstop = false;
        public volatile string strOutputText;
        private Form1 form1;
        public CTextOutput(Form1 form1, string strText)
        {
            this.form1 = form1;
            strOutputText = strText;
        }

        public void WriteText()
        {
            form1.AddText(strOutputText);
            while (shouldstop == false)
            {
                Thread.Sleep(100); //输出线程休眠100毫秒
                form1.AddText(strOutputText);
            }
            form1.AddText("自动填表线程终止");
        }
    }
}

(2)Form1类,主线程类

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace AccessControlInThread
{
    public partial class Form1 : Form
    {
        Thread fillListThread;
        CTextOutput ctoFillList;
        public Form1()
        {
            InitializeComponent();
            ctoFillList = new CTextOutput(this, "default");
            String th = Thread.CurrentThread.ManagedThreadId.ToString();

            MessageBox.Show("主线程是 " + th);
        }

        private delegate void AddTextDelegate(string text);
        public void AddText(string text)
        {
            if (ltbViewText.InvokeRequired)
            {

                String th1 = Thread.CurrentThread.ManagedThreadId.ToString();
               
                MessageBox.Show("true当前线程是:"+th1);
                AddTextDelegate td = AddText;
                ltbViewText.Invoke(td, text);
            }
            else
                ltbViewText.Items.Add(text);
                String th = Thread.CurrentThread.ManagedThreadId.ToString();
                
                MessageBox.Show("else当前线程是 "+th);
        }

        private void btnStartThread_Click(object sender, EventArgs e)
        {
            ltbViewText.Items.Clear();
            ctoFillList.shouldstop = false;
            ctoFillList.strOutputText = tbText.Text;
            fillListThread = new Thread(ctoFillList.WriteText);
            fillListThread.IsBackground = true;
            fillListThread.Start();
        }

        private void btnEndThread_Click(object sender, EventArgs e)
        {
            ctoFillList.shouldstop = true;
            fillListThread.Join(0);
        }

        private void tbText_TextChanged(object sender, EventArgs e)
        {
            ctoFillList.strOutputText = tbText.Text;
        }
    }
}

参考文献

1、何波,傅由甲;C#网络程序编程(第二版);清华大学出版社,2019.

 2、(34条消息) C# 委托 回调 操作UI主线程 学习笔记_SumC Ronnie的博客-CSDN博客

3、C#线程(异步委托) - 唧唧复唧唧木兰当户织 - 博客园 (cnblogs.com)

 4、C#委托及事件 - doscn - 博客园

5、(34条消息) C#使用委托调用主线程上的控件_浮生若梦的专栏-CSDN博客

6、C#委托和事件的使用示例 - vickylinj - 博客园

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值