C# 解决 System.InvalidOperationException:“线程间操作无效: 从不是创建控件“...”的线程访问它。”

这篇具有很好参考价值的文章主要介绍了C# 解决 System.InvalidOperationException:“线程间操作无效: 从不是创建控件“...”的线程访问它。”。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

出错代码

// Form1.cs
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Task.Run(() => // 模拟另一线程
        {
            // 在另一线程内做一些耗时操作
            //...
            string result = "...";
            
            // 输出结果(将引发异常)
            textBox1.Text = result; // System.InvalidOperationException
        });
    }
}

异常信息

中文:
System.InvalidOperationException:“线程间操作无效: 从不是创建控件“textBox1”的线程访问它。”

英文:
System.InvalidOperationException: Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.

解决办法

方法1(不推荐):禁用跨线程检查

使用 Control.CheckForIllegalCrossThreadCalls = false;

例如:

// Form1.cs
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        Control.CheckForIllegalCrossThreadCalls = false; // 禁用跨线程检查
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Task.Run(() => // 模拟另一线程
        {
            // 在另一线程内做一些耗时操作
            //...
            string result = "...";
            
            // 输出结果(不会引发异常)
            textBox1.Text = result;
        });
    }
}

方法2:使用委托

使用 Control 基类的 InvokeBeginInvoke 方法,来执行禁止跨线程的代码。

例如:

// Form1.cs
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Task.Run(() => // 模拟另一线程
        {
            // 在另一线程内做一些耗时操作
            //...
            string result = "...";
            
            // 输出结果(不会引发异常)
            this.Invoke(() =>
            {
                textBox1.Text = result;
            });
        });
    }
}

或:

// Form1.cs
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Task.Run(() => // 模拟另一线程
        {
            // 在另一线程内做一些耗时操作
            //...
            string result = "...";
            
            // 输出结果(不会引发异常)
            this.Invoke((MethodInvoker)delegate
            {
                textBox1.Text = result;
            });
        });
    }
}

使用参数进行传递:

// Form1.cs
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Task.Run(() => // 模拟另一线程
        {
            // 在另一线程内做一些耗时操作
            //...
            string result = "...";
            
            // 输出结果(不会引发异常)
            this.Invoke((string text, int length) =>
            {
                textBox1.Text = $"Text={text}, Length={length}";
            }, result, result.Length);
        });
    }
}

不使用 lambda 表达式的写法:

// Form1.cs
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Task.Run(() => // 模拟另一线程
        {
            // 在另一线程内做一些耗时操作
            //...
            string result = "...";
            
            // 输出结果(不会引发异常)
            this.Invoke(new SetTextEvent(SetText), result, result.Length);
        });
    }

    private void SetText(string text, int length)
    {
        textBox1.Text = $"Text={text}, Length={length}";
    }

    private delegate void SetTextEvent(string text, int length);
}

使用 BeginInvoke 方法的情形,与使用 Invoke 方法类似。二者区别是:Invoke 方法会在主线程(这里指 GUI 线程)内完成工作;BeginInvoke 会在一个新的线程内完成工作(当然,这不会报错)。

方法3:使用 BackgroundWorker 完成整个耗时过程(不仅是改变 GUI)

例如:

// Form1.cs
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        using (BackgroundWorker backgroundWorker = new BackgroundWorker())
        {
            backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
            backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
            backgroundWorker.RunWorkerAsync(); // 可以传入参数
        }

        // 后续过程(不会被 BackgroundWorker 阻塞,即不会等待其完毕再执行)
        // ...
    }

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        //e.Argument // 可以取得传入的参数

        // 模拟耗时操作
        //...
        string result = "...";
        
        // 传递结果
        e.Result = result;
    }

    private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        textBox1.Text = e.Result.ToString(); // 输出结果
    }
}

另一个例子,带有进度反馈,且支持取消:
见我的另一篇文章:C# BackgroundWorker 简单示例文章来源地址https://www.toymoban.com/news/detail-517788.html

参考资料

  • https://zhuanlan.zhihu.com/p/568602274

到了这里,关于C# 解决 System.InvalidOperationException:“线程间操作无效: 从不是创建控件“...”的线程访问它。”的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • System.InvalidOperationException:“未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序。”

    在电脑上安装 access驱动,Microsoft.ACE.OLEDB.12.0对应的是office 2010 需要安装64位的就安装64位  将目标平台改为X64 插入数据代码 public static String PathByConfig = Directory.GetCurrentDirectory();         public static String Path_Str = PathByConfig +\\\"\\\\test.accdb\\\";         String connStr = @\\\"Provider= Microsoft.ACE

    2024年02月04日
    浏览(27)
  • System.InvalidOperationException:“未在本地计算机上注册“Microsoft.Ace.OLEDB.12.0”提供程序。

    升级Office365 64位后,原C#与Access做的程序突然不能使用了,网上一些教程大多是下载office驱动程序,安装数据连接组件(官网下载链接),个人觉得电脑上已经安装完整的Access了,组件应该也一同安装了,后来调整(项目--属性--生成--目标平台),将首选32位勾选掉,再编译就

    2024年02月12日
    浏览(34)
  • C#调用SqlSugar操作达梦数据库报错“无效的表或视图名”

      安装达梦数据库后,使用SqlSugar连接测试数据库并基于DBFirst方式创建数据库表对应的类,主要代码如下:   运行到CreateClassFile函数时报如下错误:   通过达梦管理工具查看数据库,PERSON数据库下有ADDRESS表,不清楚为什么报错。   百度错误信息,检索结果中介绍可

    2024年01月25日
    浏览(39)
  • C#线程操作UI控件

    在写winform程序时候,如果时间长的操作不用线程操作。那么会卡死UI,点击界面就体现为未响应。为此需要对耗时操作用线程处理,比如检验的监听程序就是一个死循环,不停检查文件夹或数据库又没有数据,然后上传。如果不时有线程,在数据多的情况,程序是基本点不动

    2024年02月13日
    浏览(26)
  • C# 使用屏障来使多线程并发操作保持同步

    以下是微软官方对屏障类的介绍,System.Threading.Barrier 可用来作为实现并发同步操作的基本单元,让多个线程(参与者)分阶段并行处理目标算法。在达到代码中的屏障点之前,每个参与者将继续执行,屏障表示工作阶段的末尾;单个参与者到达屏障后将被阻止,直至所有参与者

    2024年01月24日
    浏览(35)
  • 关于python中的键鼠操作在游戏中无效的解决办法

    下载pydirectinput库  添加需要的键鼠操作 最最重要的是以管理员方式运行程序 运行代码就可以实现键鼠操作了,根本不用买幽灵键鼠什么外设    

    2024年02月20日
    浏览(32)
  • C#中Dictionary与ConcurrentDictionary解锁多线程操作安全之道

      在C#中, Dictionary 是一个常见的字典类型,但它不是线程安全的。为了在多线程环境中确保安全的操作,我们可以使用 ConcurrentDictionary ,这是一个专门设计用于多线程场景的线程安全字典。 首先,我们来看一个使用普通的 Dictionary 的例子。在这个例子中,我们创建一个 D

    2024年01月22日
    浏览(32)
  • 蓝屏终止代码SYSTEM-THREAD-EXCEPTION-NOT-HANDLED如何解决 终止代码:SYSTEM-THREAD-EXCEPTION-NOT-HANDLED 失败的操作:nvlddmk

    蓝屏终止代码SYSTEM-THREAD-EXCEPTION-NOT-HANDLED如何解决 终止代码:SYSTEM-THREAD-EXCEPTION-NOT-HANDLED 失败的操作:nvlddmkm.sys 显示英伟达显卡有关的错误。 若是有超频,降压等,建议恢复正常,包括主板自动超频功能。 然后到设备供应商的官网更新一下bios,覆盖安装一下显卡驱动,请勿

    2023年04月08日
    浏览(28)
  • Unity报错:InvalidOperationException:You are tring to read lnput using the UnityEngine. ……的解决办法

    问题描述: 我在运行steam VR的Interaction_Example时报错,其中unity为2021.3.6f1c1,steam VR(2.7.3),头显为HTC Vive pro2。报错具体内容如下: InvalidOperationException: You are trying to read Input using the UnityEngine.Input class, but you have switched active Input handling to Input System package in Player Settings. UnityEngine

    2024年02月12日
    浏览(37)
  • C# System.MissingMethodException

    C#应用程序工程调用C#类库工程生成的动态链接库调试时,在方法公开,实参形参数量对应的情况下报错: System.MissingMethodException   HResult=0xFFFFFFFF   Message=找不到方法…… 软件结构如下:         调试时,当软件运行到ApplicationProgramFunction方法即会直接报错,不会执行方法

    2024年01月20日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包