C# 使用调用或后台工作程序更新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

我正在做一个学校的项目,我需要做一些温度测量。任务是随机创建一些温度,然后计算平均值。我的代码如下所示,但线程有问题。在创建窗口句柄之前,不能将其称为对象。我搜索了一下网络,发现后台工作人员更适合更新UI。我还不太擅长编程,因为我刚开始上学

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();
    }