C#使用委托跨线程调用控件方法

概述

昨天在写一个串口自动调试工具的时候,需要实现按下一个按钮开始自动调试,按下中止按钮,中止调试。
那么这就需要自动调试的过程是非阻塞式的。
以前遇到需要多任务运行的时候都是使用非阻塞式轮询,这次打算使用多线程进行,结果遇到了一系列问题,所幸最终解决了,并记录如下。

应用场景

任何需要多线程运行任务的情况,比如抽奖程序,按下开始,再次按下停止等等,且在各种游戏中运用广泛。

目标

1、使用一个按钮启动并关闭子线程,并对本线程的TextBox进行控制,每隔1秒钟循环打印1~10;

开始

多线程

首先,写了一个按钮的方法,然后生成子线程,通过MainWindow.mainWindow.sendtomsgbox(string msg)方法将信息打印在公屏textBox上。

public partial class MainWindow : Form {
    // 单例
    static public MainWindow mainWindow;

    private string currentTime;

    private bool isAutoCalibStart;

    // 自动校准子线程
    private AutoCalibThread autoCalibThread;
    Thread childThread;

    public MainWindow() {
        InitializeComponent();
        mainWindow = this;

        TheadInit();
    }

    private void MainWindow_Load(object sender, EventArgs e) {}

    private void TheadInit() {
        autoCalibThread = new AutoCalibThread();
        childThread = new Thread(new ThreadStart(autoCalibThread.StartautoCalib));

        isAutoCalibStart = false;
    }

    private void AutoCalibStartButton_Click(object sender, EventArgs e) {
        if (isAutoCalibStart) {
            isAutoCalibStart = false;
            childThread.Abort();
        } else {
            isAutoCalibStart = true;
            if (childThread != null) {
                childThread.Start();
            }
        }
    }

    // 发送消息到消息框
    public void SendToMsgBox(string msg, bool isNextLine = true) {
        if (isNextLine) {
            this.MsgBox.AppendText(msg + "\r\n");
        } else {
            this.MsgBox.AppendText(msg);
        }
    }
}

然后出现了第一个问题:“线程间操作无效: 从不是创建控件的线程访问它”。

好吧,仔细一想也是,这种窗口控件的访问本质上不是线程安全的。如果有两个或多个线程操作同一控件的状态,则可能会迫使该控件进入一种不一致的状态。还可能出现其他与线程相关的 bug,包括争用情况和死锁。因此,确保以线程安全方式访问控件非常重要。[参考自互联网]

于是,想到的第一个方法是,把textBox控件独立到一个新的线程,别的线程需要打印信息,需要通过接口给该类传输数据,该类会将数据保存在Buffer中,然后通过定时访问的方式将Buffer中的数据载入到控件里。也就是中间多加了个Buffer缓存,避免了多个线程调用方法直接控制控件。

但是还是打算看看网上的方法,一个是启用线程间操作。

CheckForIllegalCrossThreadCalls = false;

另一个是使用委托。感觉第一个等于没解决,无异于看见BUG不管。遂选择使用较为复杂的委托。

委托

参考网上N个资料和例程,依然不断报错“线程间操作无效: 从不是创建控件的线程访问它”。也就是说委托并没有配置成功,最后不断翻看总算解决了,记录如下:

//以下内容由三个类中的代码块拼接而成
//声明委托,注意委托参数表需要与被委托参数表一致
class DelegateCollection
{
    public delegate void MsgSendDategate(string msg, bool isNextLine = true);
}

//声明子线程,并在子线程类中定义委托以方便直接调用
class AutoCalibThread
{

    public DelegateCollection.MsgSendDategate msgSendDategate;

    public void StartautoCalib()
    {
        for (int i = 1; i < 10; i++)
        {
            Thread.Sleep(1000);
            if (msgSendDategate != null)
            {
                msgSendDategate(i.ToString());
            }
        }

    }
}

//重写任务函数(即被委托函数)[注意该函数在拥有被调用控件地类中]
public void SendToMsgBox(string msg, bool isNextLine = true)
{

    if (this.MsgBox.InvokeRequired)
    {
        BeginInvoke(autoCalibThread.msgSendDategate, new object[] { msg, isNextLine });
    }
    else
    {
        if (isNextLine)
        {
            this.MsgBox.AppendText(msg + "\r\n");
        }
        else
        {
            this.MsgBox.AppendText(msg);
        }
    }
}

//进行委托绑定[注意该函数在拥有被调用控件地类中]
private void TheadInit()
{
    autoCalibThread = new AutoCalibThread();
    autoCalibThread.msgSendDategate = new DelegateCollection.MsgSendDategate(SendToMsgBox);
    childThread = new Thread(new ThreadStart(autoCalibThread.StartautoCalib));
}

小错误

使用委托成功地让子线程控制了其他线程地状态,但还是遇到了个小问题,在杀死线程后重新启动出现报错“线程正在运行或被终止;它无法重新启动。”很容易可以想到,使用Abort方法后,线程处在死亡状态,生命周期已经结束。需要重新实例化一个线程,于是将实例化代码从初始化函数移动到启动函数即可。

结果

评论

  1. erotik
    4 年前
    2020-11-13 20:22:06

    Hi Dear, are you in fact visiting this web site daily, if so then you will absolutely get good experience. Fayre Jefferey Adriene

  2. porno
    4 年前
    2020-11-13 22:19:02

    Thank you! Actually, I had someone design it for me. Matilde Agustin Belsky

  3. porno
    4 年前
    2020-11-14 6:36:17

    I cannot thank you enough for the article post. Really looking forward to read more. Keep writing. Karlotta Lucian Manchester

发送评论 编辑评论


|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇