10

解决了

看来奥利弗是对的。经过几次尝试后,我得到了异常,并且在调试模式下我确定了。所以这必须与时间有关。您还应该检查 Matthew wattsons 的答案;)

例子

首先是一个小例子,可以解释我的困惑。

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 testCrossThreading
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            new Thread(ThreadJob).Start();
        }

        void ThreadJob()
        {
            //label1.Text = "1";
            changeText(label1, "1");
        }

        void changeText(Label L, String message)
        {
            L.Text = message;
        }
    }
}

问题

所以现在我的问题是:如果我label1.Text = "1";在函数“ThreadJob”中取消注释,那么我会按预期得到一个跨线程异常。但是,如果我留下评论,就像示例显示它确实有效。但为什么?该函数由子线程调用,我不调用任何东西。因此,更改标签 imo 文本的仍然是子线程,而不是 GUI 线程。还是我错过了什么?

我会这样写。

void ThreadJob()
        {
            Action a = () => label1.Text = "1";
            this.Invoke(a);
        }
4

2 回答 2

7

我认为这只是一个时间问题。如果您尝试从非 gui 线程更新 gui 元素,则可能会引发跨线程异常。您甚至可以通过调用禁用整个跨线程异常

Form.CheckForIllegalCrossThreadCalls = false;

但是在异常消失后,进一步的行为是未定义的,并且可能导致非常微妙的错误。因此,将异常作为代码异味的提示,但请注意,有时即使应该抛出异常也不会抛出异常。

于 2013-03-15T10:34:45.940 回答
2

认为您可能有竞争条件,这就是结果不同的原因。

如果您尝试更改Text当前未显示的控件的属性,则 .Net 不关心哪个线程更改它。

在您的代码中,您从构造函数启动一个线程。在设置属性的线程中的代码执行之前,实际显示表单的代码可能已经显示,也可能不显示。

当你调用一个额外的函数来设置属性时,时间会改变并暴露竞争条件。

您可以通过Thread.Sleep(100)ThreadJob().

于 2013-03-15T10:42:36.133 回答