在WPF中,可以使用类似的东西:
Application.Current.Dispatcher.BeginInvoke(new Action(() => Form1.grid.Items.Refresh()));
访问主线程之外的UI函数。但是在Winforms中,没有相同的功能。从我的“工作”线程访问我的Form1类中存在的BindingList最简单的方法是什么?目前,在尝试访问“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”。我在单独线程中的方法没有“调用”。
这是我目前为止的代码示例。
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");
}
}
}
}
我认为这里的具体问题是当我将Records添加到Forms1.record_list时。我不确定如何在不导致跨线程错误的情况下将项添加到该列表...
答案 0 :(得分:4)
您必须仅从UI线程访问您的UI。但您可以使用Control.Invoke
方法 - Form
是Control
- 来确保您的代码是从UI线程运行的。
此外,您有一个静态BindingList
,但我认为您希望以特定形式显示该列表的内容。您应该使BindingList
成为实例成员...或获取对有效表单的引用。 Control.Invoke
方法不是静态的。
有几种方法可以做到这一点。我会这样做:
首先,在Form类中创建一个方法,将记录添加到列表中。
public void AddRecord(Record r) {
if(this.InvokeRequired) {
this.Invoke(new MethodInvoker(() => this.AddRecord(r)));
} else {
this.record_list.Add(r);
}
}
其次,您需要引用表单(在下一步中,即theForm
变量)。
然后,在您的侦听器方法中,调用AddRecord
方法,而不是直接在BindingList
中添加记录。
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);
}
}
}
答案 1 :(得分:0)
您正在寻找适用于WinForms和WPF的SynchronizationContext.Current
。
请注意,您需要从UI线程中获取其值,因为它是每个线程。
答案 2 :(得分:0)
以下内容将以winforms方式进行。曾尝试过一次。以下代码有助于从另一个线程更新UI线程中的标签。
string _string = "Call from another thread";
this.Invoke((MethodInvoker)delegate {
label1.Text = _string;
});