【问题标题】:Thread error in C# Windows FormC# Windows 窗体中的线程错误
【发布时间】:2013-07-07 15:13:32
【问题描述】:

我收到了这个错误:

“System.InvalidOperationException”类型的未处理异常 发生在 System.Windows.Forms.dll 中

附加信息:跨线程操作无效:控制 'Redlight' 从创建它的线程以外的线程访问 开。

Redlight 和 Greenlight 是图片框。 基本上,我希望它能够每秒在每张图片之间交替。 我在这个网站上搜索了类似的错误,我发现它与“Invoking”有关,但我什至不知道那是什么,有人能启发我吗?

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

namespace EMCTool
{
    public partial class EMCTool_MainForm : Form
    {
        bool offOn = false;

        public EMCTool_MainForm()
        {
            InitializeComponent();
        }

        private void EMCTool_MainForm_Load(object sender, EventArgs e)
        {
            System.Threading.Timer timer = new System.Threading.Timer(new System.Threading.TimerCallback(timerCallback), null, 0, 1000);
        }

        private void timerCallback(object obj)
        {
            if (offOn == false)
            {
                Redlight.Show();
                offOn = true;
            }
            else
            {
                Greenlight.Show();
                offOn = false;
            }
        }
    }
}

【问题讨论】:

    标签: c# winforms


    【解决方案1】:

    当您尝试从未在其上创建的任何线程更新 UI 元素时,您会收到跨线程错误。

    Windows 窗体中的控件绑定到特定线程并且不是线程安全的。因此,如果您从不同的线程调用控件的方法,则必须使用控件的调用方法之一将调用编组到正确的线程。此属性可用于确定是否必须调用调用方法,如果您不知道哪个线程拥有控件,这可能很有用。

    更多信息请参考here

    试试这个。这对我来说很好用

       if (pictureBoxname.InvokeRequired)
                        pictureBoxname.Invoke(new MethodInvoker(delegate
                        {
              //access picturebox here
                        }));
                    else
            {
    
      //access picturebox here
    }   
    

    【讨论】:

    • 哦,好吧,这个 Invoke 东西是如何工作的,它对我有什么作用?编辑:我已经测试过并且有效。
    • Invoke 方法委托 UI 相关的处理在它创建的线程上完成,即 UI 线程。
    • @user1880591 它将您的调用发送到创建控件的线程,然后由那个线程完成工作。
    • 调用是否占用大量资源和性能?我觉得我必须对表单上的所有内容使用调用。
    • @user1880591 使用 Windows 窗体计时器而不是 System.Threading.Timer 将首先避免所有跨线程操作...
    【解决方案2】:

    在 WinForms 项目中最好使用 System.Windows.Forms.Timer,因为它会自动在 UI 线程上调用 Tick 事件:

    private System.Windows.Forms.Timer _timer;
    
    private void EMCTool_MainForm_Load(object sender, EventArgs e)
    {
        _timer = new System.Windows.Forms.Timer { Interval = 1000 };
        _timer.Tick += Timer_Tick;
        _timer.Start();
    }
    
    private void Timer_Tick(object sender, EventArgs e)
    {
        if (offOn) {
            Greenlight.Show();
        } else {
            Redlight.Show();
        }
        offOn = !offOn;
    }
    

    【讨论】:

      【解决方案3】:

      替代解决方案是使用具有 SynchronizingObject 属性的 System.Timers.Timer 进行设置,这样它就可以工作了:

      timer.SynchronizingObject = This
      

      或者使用 System.Windows.Forms.Timer,因为它不会引发异常(它会在 UI 线程上引发 Tick 事件)。

      【讨论】:

        猜你喜欢
        • 2016-03-09
        • 2014-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-17
        • 1970-01-01
        • 2012-06-15
        • 1970-01-01
        相关资源
        最近更新 更多