为什么我可以在没有跨线程异常的情况下从线程中的表单访问控件? [英] Why can I access controls from a form in a thread without cross thread exception?

查看:108
本文介绍了为什么我可以在没有跨线程异常的情况下从线程中的表单访问控件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常,当您访问线程中的控件时,最终会遇到一些跨线程异常.在我的C#WinForms应用程序中,我有一个图片框和一个工具条标签,它们不会导致该异常.我不明白为什么,有人可以向我解释一下吗?

Usually, when you access controls in a Thread you end up with some cross thread exceptions. In my C# WinForms Application I have a picture box and a toolstriplabel which do not cause that exception. I don't understand why, can anybody explain this to me?

这里有一些代码说明:

在主要形式中,我有一个图片框和一个工具条标签.另外,我还引用了另一个窗体,该窗体没有控件,也没有其他源代码.然后在主要形式中,还有另一个与线程一起工作的对象.该线程可以引发三个不同的事件,主要形式是预订这三个事件.

In the main form I have a picturebox and a toolstriplabel. Also I have a reference to another Form, which has no controls and no additional source code. And then in the main form there is another object which works with a thread. This thread can raise three different events and the main form is subscribed to these three events.

  • Event1导致toolstriplabel更新(带有来自线程的一些信息).
  • Event2导致图片框更新(带有线程中的新图片).

Event1和Event2可以正常工作.我不使用任何调用方法,我直接更改了Text和BackgroundImage属性,而没有跨线程异常.

Event1 and Event2 work perfectly fine. I do not use any invoke methods, I directly change Text and BackgroundImage properties without cross thread exception.

  • 事件3会带来麻烦.它应该显示其他形式,但是我收到了交叉therad例外.仅当我使用BeginInvoke显示表单时,它才起作用.

那是为什么?

多线程处理是通过 MJPEGStream 对象完成的.我订阅了该MJPEGStream对象的 NewFrame 方法.

The multithreading is done by an MJPEGStream object. I subscribe the NewFrame method of that MJPEGStream object.

public partial class Form1 : Form
{
    private CAM cam;

    private PeekWindow frmPeekWindow;

    public Form1()
    {
        InitializeComponent();

        cam = new CAM();
        cam.NewImageMessageEvent += new NewImageEventHandler(cam_NewImageMessageEvent);
        cam.DetectionEvent += new DetectionEventHandler(cam_DetectionEvent);
        cam.FpsChangedMessageEvent += new FpsChangedEventHandler(cam_FpsChangedMessageEvent);
        cam.DetectionThreshold = (float)this.numDetectionThreshold.Value;

        frmPeekWindow = new PeekWindow();

        // without the next two lines, frmPeekwindow.Show() won't work if called in an event
        frmPeekWindow.Show();
        frmPeekWindow.Hide();
    }

    void cam_FpsChangedMessageEvent(object sender, FpsChangedEventArgs e)
    {
        lblFPS.Text = string.Format("fps: {0:0.0}", e.FPS);
    }

    void cam_DetectionEvent(object sender, DetectionEventArgs e)
    {
        if (chkEnablePeakWindow.Checked)
        {
            if (frmPeekWindow.InvokeRequired)
            {
                frmPeekWindow.Invoke((MethodInvoker)delegate()
                {
                    frmPeekWindow.Show();
                    frmPeekWindow.setImage(e.Image);
                });
            }
            else
            {
                frmPeekWindow.Show();
                frmPeekWindow.setImage(e.Image);
            }
        }
    }

    void cam_NewImageMessageEvent(object sender, NewImageEventArgs e)
    {
        picStream.BackgroundImage = e.Image;
    }
}

这是CAM类:

class CAM
{
    private object lockScale = new object();

    private MJPEGStream stream;
    private Bitmap image;

    public event NewImageEventHandler NewImageMessageEvent;
    public event FpsChangedEventHandler FpsChangedMessageEvent;
    public event DetectionEventHandler DetectionEvent;

    // configure (login, pwd, source)
    public CAM()
    {
        this.stream = new MJPEGStream("...");
        this.stream.Login = "...";
        this.stream.Password = "...";
        this.stream.NewFrame += new NewFrameEventHandler(OnNewFrame)
    }

    private void OnNewFrame(object sender, NewFrameEventArgs ev)
    {
        try
        {
            FpsChangedMessageEvent(this, new FpsChangedEventArgs(10));

            // get image
            image = ev.Frame;
            NewImageMessageEvent(this, new NewImageEventArgs(new Bitmap(image)));

            DetectionEvent(this, new DetectionEventArgs(new Bitmap(image)));
        }
        catch (Exception ex)
        {
            Console.Out.WriteLine(ex.Message);
        }
    }
}

推荐答案

您不会遇到跨线程异常,但这并不意味着这是一个安全的操作.您的控件总是有可能变得不稳定.您只是不知道何时会发生.

You won't get cross thread exception, but it doesn't mean that this is a safe operation. There is always a possibility for your control to go unstable. You just don't know when it will happen.

请参阅Microsoft的以下说明. http://msdn.microsoft.com/en-us/library/ms171728.aspx

See the following explanation from Microsoft. http://msdn.microsoft.com/en-us/library/ms171728.aspx

访问Windows Forms控件本质上不是线程安全的.如果你 有两个或多个线程来控制控件的状态,它是 可能会迫使控件进入不一致状态.其他 与线程相关的错误是可能的,例如竞争条件和 僵局.确保访问控件很重要 以线程安全的方式执行.

Access to Windows Forms controls is not inherently thread safe. If you have two or more threads manipulating the state of a control, it is possible to force the control into an inconsistent state. Other thread-related bugs are possible, such as race conditions and deadlocks. It is important to make sure that access to your controls is performed in a thread-safe way.

这篇关于为什么我可以在没有跨线程异常的情况下从线程中的表单访问控件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆