从 backgroundworker 中的循环更新文本框

Update textbox from loop in backgroundworker

我知道有人问过这个问题(至少从目前为止我在这里发现的情况来看是这样),但我实在想不通。已经用msdn的例子试过了,但还是没有成功。这是我正在尝试做的事情:我有一个连接到 TLL 标尺的 USB 计数器。我想在循环中不断读取值并将读数写入文本框而不阻塞主 UI。我从其他问题中知道我应该使用 Invoke 或 Backgroundworker,但还没有真正找到一个我理解并可以用来相应地调整我的代码的示例。代码没有任何修改,为简单起见,如下:

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

namespace USB_Counter
{
public partial class Form1 : Form
{
    [DllImport("HS_UC.dll", EntryPoint = "HS_UC_Close")] //+further DLL imports (driver for USBCounter)
    public static extern int HS_UC_Close(int CounterNo);

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e) //initialize COunter
    {
        int A = HS_UC_Init(1, 3);
        string B = Convert.ToString(A);
        MessageBox.Show(B); //to check if there is no error
    }

    private void button2_Click(object sender, EventArgs e)
    {
        HS_UC_SetDistCode(1, 20, 40, 4, 0, 0); //set Reference
        HS_UC_SetRefMode(1, 1);
    }

    private void button3_Click(object sender, EventArgs e)
    {
        int a = 1;
        int A = 0; //variable that takes counter value (the one I want)
        int B = 0; //variable that takes counter status
        do
        {
            HS_UC_GetCounter(1, ref A, ref B);
            decimal C = (Convert.ToDecimal(A) / 100);
            textBox1.Text = "Das ist: " + C;
            textBox1.Update();
        } while (a == 1);
    }
}

}

现在它可以按预期工作,但如前所述,它会阻塞主 UI 线程(很明显)。如果有人发现类似的问题以及一些有用的提示以开始使用此多线程主题或直接关于我的问题的任何有用提示,将不胜感激。 来自柏林的问候, 克里斯

更新:通过以下尝试使其正常工作:

private void Counter_Read()
    {
        int a = 1;
        do
        {
            int A = 0;
            int B = 0;
            HS_UC_GetCounter(1, ref A, ref B);
            decimal C = (Convert.ToDecimal(A) / 100);
            UpdateTextBox(C);
        } while (a == 1);
    }

    public void UpdateTextBox(decimal C)
    {
        if (InvokeRequired)
        {
            this.Invoke(new Action<decimal>(UpdateTextBox), new object[] { C });
            return;
        }
        textBox1.Text = "Das ist: " + C;
        textBox1.Update();

    }

    private void button3_Click(object sender, EventArgs e)
    {
        System.Threading.Thread t = new System.Threading.Thread(() => Counter_Read());
        t.Start();
    }

从那里我得到一个十进制输出,我不断更新它并且仍然能够使用其他按钮。

你可能想看看这个 link MSDN.

但是,一个快速提示是为 DoWork 事件注册一个方法,然后执行 RunAsynchronously 方法。

将循环代码外包到一个方法中。在方法内部,您需要使用 BeginInvoke 写入 TextBox

private void DoTheLoop()
{
    int a = 1;
    int A = 0; //variable that takes counter value (the one I want)
    int B = 0; //variable that takes counter status
    do
    {
        HS_UC_GetCounter(1, ref A, ref B);
        decimal C = (Convert.ToDecimal(A) / 100);
        textBox1.BeginInvoke(new Action(()=>{textBox1.Text = "Das ist: " + C;}));
    } while (a == 1);
}

第一个版本使用正常Thread:

创建线程并在单击 button3 时使用新方法启动它

private void button3_Click(object sender, EventArgs e)
{
    System.Threading.Thread t = new System.Threading.Thread(()=>DoTheLoop());
    t.Start();
}

这不应阻止您的 GUI,文本框将显示值

第二个版本 使用 BackgroundWorker:

创建一个 BackgroundWorker 并注册 DoWork 事件:

System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();

private void Form1_Load(object sender, EventArgs e)
{
    worker.DoWork += Worker_DoWork;
}

在事件处理程序内部调用相同的方法DoTheLoop():

private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
    DoTheLoop();
}

在按钮点击事件中启动worker:

private void button1_Click(object sender, EventArgs e)
{
    worker.RunWorkerAsync();
}

最后结果相同:)