如何从不同的线程访问变量?

4

出现错误:跨线程操作无效:从创建该控件的线程以外的线程访问控件“label1”。

代码:

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.Threading;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        string CONNECTING = "Connecting to server...";
        string GETTING_DATA = "Getting data...";
        string CONNECT_FAIL = "Failed to connect!";
        string CONNECT_SUCCESS = "Connection established!";

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Thread t1 = new Thread(run);
            t1.Start();
        }

        public void run() {
            label1.Text = CONNECTING;
        }
    }
}

我该如何正确地解决这个问题?我尝试使用CheckForIllegalCrossThreadCalls = false;,但显然会导致错误。
我还想知道如何停止线程,因为在该函数外部无法访问该线程。
提前感谢!

那不是一个全局变量,你应该调用它。 - Sayse
可能是重复的问题:跨线程操作无效 - Hans Passant
2个回答

8

尝试使用BeginInvoke:

public void run() 
{
    label1.BeginInvoke(new Action(() =>
    {
        label1.Text = CONNECTING;
    }));
}

只有UI线程才能在Windows Forms应用程序中更新UI元素。其他线程需要使用BeginInvoke来更新UI。

原文:我以为这是WPF应用程序,并建议使用this.Dispatcher,但Dispatcher不适用于Windows Forms应用程序。


这不是一个 WPF 应用程序,你可以清楚地看到代码片段中使用了 Form 类。 - Hans Passant
啊,你当然是正确的,我没看到。已更新答案! - Alden
如何获取变量而不是设置它? - TheTank20

5

在不同线程中访问控件

WinForms App 中,你只能直接从创建它的线程访问Control。 要执行这样的任务,你需要使用ControlInvokeRequired属性来判断是否必须使用Invoke来强制调用原始线程中的操作。

可以从任何线程(包括原始线程)访问的公共方法如下:

public void run() {
    if (label1.InvokeRequired) //Is this method being called from a different thread
        this.Invoke(new MethodInvoker(()=> label1.Text = CONNECTING));
    else //it's cool, this is the original thread, procceed
        label1.Text = CONNECTING;
}


但如果您绝对确定run()方法仅从线程中调用,请考虑甚至不检查InvokeRequired并立即调用Invoke

更多信息:http://msdn.microsoft.com/en-us/library/ms171728(v=vs.80).aspx

停止进行中的线程

  • 简单地使用Threadt1.Abort();方法。这将抛出异常,强制使其在任何地方停止。这对于不执行任何长时间处理的线程非常好,因此停止它不会造成任何问题。

  • 如果您在线程中执行处理,则无法在中间停止它,那么建议您使用一个布尔值来指示该线程必须尽快取消。

private bool isCancelRequired = false;
public void run() {
     while(true) {
         //do long processing..
         if (isCancelRequired)
            break;
     }
} 


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接