从 Winforms 中的外部线程访问 UI [英] Accessing UI from outside thread in Winforms

查看:27
本文介绍了从 Winforms 中的外部线程访问 UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 WPF 中,可以使用类似的东西:

In WPF, one could use something like:

Application.Current.Dispatcher.BeginInvoke(new Action(() => Form1.grid.Items.Refresh()));

在主线程之外访问 UI 功能.然而,在 Winforms 中,没有相同的功能.从我的工作"线程访问存在于我的 Form1 类中的 BindingList 的最简单方法是什么?目前,我在尝试访问Form1.record_list"时收到以下错误:

to access UI functions outside of the main thread. In Winforms however, the same functionality isn't there. What would be the easiest way to access a BindingList that exists inside of my Form1 class from my "working" thread? Currently I getting the following error when trying to access "Form1.record_list":

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

我很感激到目前为止的帮助,但我对this.Invoke"迷失了方向.我在单独线程中的方法没有调用".

edit: I appreciate the help so far, but I'm lost on "this.Invoke". My method in the separate thread has no "Invoke".

这是迄今为止我的代码示例.

Here's an example of my code so far.

        public static void listen(IPEndPoint server_ip)
    {
        Console.WriteLine("In listen");
        while (true)
        {
            try
            {
                byte[] received_bytes = udp_client.Receive(ref server_ip);
                string received_data = Encoding.ASCII.GetString(received_bytes);
                Record record = JsonConvert.DeserializeObject<Record>(received_data);
                Form1.record_list.Add(record); //This is where I assume the problem spawns
            }

            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
    }




public partial class Form1 : Form
{
    public static BindingList<Record> record_list = new BindingList<Record> { };
    public static DataGridViewCellStyle style = new DataGridViewCellStyle();
    public Form1()
    {
        InitializeComponent();
        Thread thread = new Thread(SCMClient.connect);
        thread.IsBackground = true;
        thread.Start();
        FillData();           
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        foreach (DataGridViewRow row in dataGridView.Rows)
        {
            for (var i = 0; i < row.Cells.Count; i++)
            {
                Console.WriteLine(row.Cells[i].Value);
                if (row.Cells[i].Value as string == "OK")
                {
                    row.Cells[i].Style.BackColor = Color.Red;
                    Console.WriteLine("IF WAS TRUE");

                }
            }
        }
    }

我认为这里的具体问题是当我将记录添加到 Forms1.record_list 时.我不确定如何在不导致跨线程错误的情况下将项目添加到该列表中...

I think the specific problem here is when I add Records to the Forms1.record_list. I'm not sure how to add items to that list without causing the Cross-thread error...

推荐答案

您必须仅从您的 UI 线程访问您的 UI.但是您可以使用 Control.Invoke 方法 - FormControl - 确保您的代码从 UI 线程运行.

You MUST access your UI from your UI Thread only. But you can use the Control.Invoke method - a Form IS a Control - to ensure your code is run from the UI Thread.

此外,您有一个静态 BindingList,但我假设您想以特定形式显示该列表的内容.你应该让 BindingList 成为一个实例成员......或者获取对有效表单的引用.Control.Invoke 方法不是静态的.

Also, you have a static BindingList, but I assume you want to display the contents of that list in an specific form. You should make the BindingList an instance member instead... or get a reference to a valid Form. The Control.Invoke method is not static.

有几种方法可以做到这一点.我会这样做:

There are several ways to do so. I would do it like so:

首先,在您的 Form 类中创建一个方法,将记录添加到列表中.

First, create a method in your Form class that adds the record to the list.

public void AddRecord(Record r) {
    if(this.InvokeRequired) {
        this.Invoke(new MethodInvoker(() => this.AddRecord(r)));
    } else {
        this.record_list.Add(r);
    }
}

其次,您需要对表单有一个引用(在下一步中,就是theForm 变量).

Second, you need to have a reference to the form (in the next step, that is the theForm variable).

然后,在您的侦听器方法中,调用 AddRecord 方法,而不是直接在您的 BindingList 中添加记录.

Then, in your listener method, invoke AddRecord method instead of adding the record in your BindingList directly.

public static void listen(IPEndPoint server_ip)
{
    Console.WriteLine("In listen");
    while (true)
    {
        try
        {
            byte[] received_bytes = udp_client.Receive(ref server_ip);
            string received_data = Encoding.ASCII.GetString(received_bytes);
            Record record = JsonConvert.DeserializeObject<Record>(received_data);
            theForm.AddRecord(record); // You need a Form instance.
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
    }
}

这篇关于从 Winforms 中的外部线程访问 UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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