C# 使用调用或后台工作程序更新UI
我正在做一个学校的项目,我需要做一些温度测量。任务是随机创建一些温度,然后计算平均值。我的代码如下所示,但线程有问题。在创建窗口句柄之前,不能将其称为对象。我搜索了一下网络,发现后台工作人员更适合更新UI。我还不太擅长编程,因为我刚开始上学C# 使用调用或后台工作程序更新UI,c#,multithreading,C#,Multithreading,我正在做一个学校的项目,我需要做一些温度测量。任务是随机创建一些温度,然后计算平均值。我的代码如下所示,但线程有问题。在创建窗口句柄之前,不能将其称为对象。我搜索了一下网络,发现后台工作人员更适合更新UI。我还不太擅长编程,因为我刚开始上学 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using Syste
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.Windows.Forms;
using System.Collections;
using System.IO;
using System.Threading;
namespace Temperatur
{
public partial class Form1 : Form
{
static Random rnd = new Random();
static ArrayList tempList = new ArrayList();
static SemaphoreSlim w, e, b;
public Form1()
{
InitializeComponent();
w = new SemaphoreSlim(1);
e = new SemaphoreSlim(0);
b = new SemaphoreSlim(6);
Thread t1 = new Thread(randomNr);
t1.Start();
Thread t2 = new Thread(gennemsnit);
t2.Start();
}
public void randomNr()
{
//Thread.Sleep(100);
for (int i = 0; i < 10; i++)
{
//b.Wait();
//w.Wait();
int number = rnd.Next(36, 42);
tempList.Add(number);
listBox1.BeginInvoke((MethodInvoker)delegate
{
listBox1.Items.Add(number);
});
//w.Release();
//e.Release();
}
}
public void gennemsnit()
{
double avg = 0;
double nb = 0;
//Thread.Sleep(200);
for (int i = 0; i < tempList.Count; i++) //i < tempList.Count
{
//e.Wait();
//w.Wait();
nb += Convert.ToDouble(tempList[i]);
avg = nb / tempList.Count;
listBox2.Invoke((MethodInvoker)delegate //listbox2.invoke
{
listBox2.Items.Add(avg);
});
//w.Release();
//b.Release();
}
}
}
}
使用系统;
使用System.Collections.Generic;
使用系统组件模型;
使用系统数据;
使用系统图;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
使用System.Windows.Forms;
使用系统集合;
使用System.IO;
使用系统线程;
名称空间温度
{
公共部分类Form1:Form
{
静态随机rnd=新随机();
静态ArrayList tempList=新ArrayList();
静态信号量lim w,e,b;
公共表格1()
{
初始化组件();
w=新信号量lim(1);
e=新信号量lim(0);
b=新信号量lim(6);
螺纹t1=新螺纹(随机编号);
t1.Start();
螺纹t2=新螺纹(Gennemsint);
t2.Start();
}
公共图书馆编号(
{
//睡眠(100);
对于(int i=0;i<10;i++)
{
//b、 等待();
//w、 等待();
整数=rnd.Next(36,42);
圣殿骑士。添加(数字);
listBox1.BeginInvoke((MethodInvoker)委托
{
列表框1.项目.添加(编号);
});
//w、 释放();
//e、 释放();
}
}
公共空间
{
双平均值=0;
双nb=0;
//睡眠(200);
for(int i=0;i
BackgroundWorker确实是您所需要的。如果“报告进度”,则可以在进度报告中将对象传递给GUI线程。按如下方式设置进度报告:
BackgroundWorker bw = new BackgroundWorker();
您可能只想传递一个字符串作为对象,然后将该字符串添加到列表框中。我不确定您的代码试图做什么,但您的任务非常简单。你真的不必担心线程。为简单起见,您可以安排一个计时器,每隔1秒运行一次,然后选择一个随机数/读取温度,并在UI上更新它。如果您从窗体控件(System.Windows.forms.timer)中选择计时器,则可以直接从它启动时调用的函数更新UI。如果使用System.Timers.timer中的计时器,则应使用BeginInvoke更新列表 在创建窗口句柄之前,不能将其称为对象 不要在窗体的构造函数中启动线程。请改用Load()或show()事件:
public Form1()
{
InitializeComponent();
w = new SemaphoreSlim(1);
e = new SemaphoreSlim(0);
b = new SemaphoreSlim(6);
this.Load += new EventHandler(Form1_Load);
}
void Form1_Load(object sender, EventArgs e)
{
Thread t1 = new Thread(randomNr);
t1.Start();
Thread t2 = new Thread(gennemsnit);
t2.Start();
}
忘了说任务中需要包含线程来控制它。不过还是谢谢你的回答!谢谢它现在可以很好地处理调用和加载。但是我还是想尝试一下后台工作程序。不过,同样的情况也适用,不要从构造函数启动BackgroundWorker()。
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Here you have passed yourself any object you like. Could be your own class. Could be a string, etc.
MyClass myObject = e.UserState as MyClass;
// Then you can add it to your GUI as necessary, for example
listbox2.Items.Add(myObject);
}
public Form1()
{
InitializeComponent();
w = new SemaphoreSlim(1);
e = new SemaphoreSlim(0);
b = new SemaphoreSlim(6);
this.Load += new EventHandler(Form1_Load);
}
void Form1_Load(object sender, EventArgs e)
{
Thread t1 = new Thread(randomNr);
t1.Start();
Thread t2 = new Thread(gennemsnit);
t2.Start();
}