C# 避免从另一个线程多次调用以更新GUI

C# 避免从另一个线程多次调用以更新GUI,c#,multithreading,user-interface,C#,Multithreading,User Interface,如何使用一个Invoke方法使代码更精简 private void DecodeTHR(byte[] serialInput) { startVoltage.Invoke((MethodInvoker)(() => startVoltage.Value = serialInput[2])); endVoltage.Invoke((MethodInvoker)(() => endVoltage.Value = serialInput[3])); mode.Inv

如何使用一个Invoke方法使代码更精简

private void DecodeTHR(byte[] serialInput)
{
    startVoltage.Invoke((MethodInvoker)(() => startVoltage.Value = serialInput[2]));
    endVoltage.Invoke((MethodInvoker)(() => endVoltage.Value = serialInput[3]));
    mode.Invoke((MethodInvoker)(() => mode.SelectedIndex = serialInput[4]));

    if (serialInput[5] == 255)
        assistLevelTH.Invoke((MethodInvoker)(() => assistLevelTH.SelectedIndex = 0));
    else
        assistLevelTH.Invoke((MethodInvoker)(() => assistLevelTH.SelectedIndex = serialInput[5] + 1));

    if (serialInput[6] == 255)
        speedLimitTH.Invoke((MethodInvoker)(() => speedLimitTH.SelectedIndex = 0));
    else
        speedLimitTH.Invoke((MethodInvoker)(() => speedLimitTH.SelectedIndex = serialInput[6] - 14));

    startCurrentTH.Invoke((MethodInvoker)(() => startCurrentTH.Value = serialInput[7]));

    // RestartPort();

    if (next_op == rdSingle)
        MessageBox.Show("Throttle Handle flash read successful", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
    else
    {
        MessageBox.Show("Flash read successful", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
        next_op = rdIgnore;
    }
}
到目前为止,我找不到任何其他方法,但我确信有一种方法可以让您在该方法中只需进行一次调用,然后就可以从主窗体类中更新任意数量的GUI组件


既然我有很多这样的函数,有人能给我一个使用我的代码的例子吗?

既然你没有执行任何繁重的工作,就把所有的东西都打包在一个调用中吧。最好只调用表单而不是它的某个控件,因为该控件无论如何都会查找父表单

请记住也要检查invokererequired,因为如果不需要,您不想调用。实际上,通过检查invokererequired,您可以使您的方法调用自身:

private void DecodeTHR(byte[] serialInput)
{
    if(this.InvokeRequired)
    {
        this.Invoke((MethodInvoker)(() => DecodeTHR(serialInput)));
        return; //This is to ensure that the method does not execute twice.
    }

    startVoltage.Value = serialInput[2];
    endVoltage.Value = serialInput[3];
    mode.SelectedIndex = serialInput[4];

    if (serialInput[5] == 255)
        assistLevelTH.SelectedIndex = 0;
    else
        assistLevelTH.SelectedIndex = serialInput[5] + 1;

    if (serialInput[6] == 255)
        speedLimitTH.SelectedIndex = 0;
    else
        speedLimitTH.SelectedIndex = serialInput[6] - 14;

    startCurrentTH.Value = serialInput[7];

    // RestartPort();

    if (next_op == rdSingle)
    {
        MessageBox.Show("Throttle Handle flash read successful", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
    else
    {
        MessageBox.Show("Flash read successful", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
        next_op = rdIgnore;
    }
}

不要调用。将值写入一些共享变量。让GUI通过计时器轮询这些变量的Udpates。对这些变量的所有调用应用一些锁定,当然,为什么还要在后台线程中运行呢?据我所知,您没有执行任何繁重的计算/阻塞任务。@VisualIncent该函数在SerialPort.DataReceived事件处理程序中运行。有关更简单的调用方法,请参阅下面的答案。因此,这是最初调用DecodeTHR函数的方法。这样做对吗?或者我总是要像递归函数一样从函数内部调用Invoke?我更新了DataReceived和DecodeTHR中的GUI控件。DataReceived也是生成第二个线程的事件。@UnlimitedTime:首先,最好将事件本身保留为多线程。也就是说,不要援引它回答您的问题:您不必从自身内部调用DecodeTHR,但是如果您想在图像中这样做,那么您必须这样做:尝试将所有GUI更新代码放在一个调用中。最好将它们放在您调用的另一个方法中,就像上面我共享的链接一样。另外,注意返回;应该只在从内部调用方法时使用。因此,正如我所想,我被迫将一些代码放在另一个方法中。基本上,我在DataReceived事件处理程序中调用了4-5个方法,对于这些方法,一切正常,但是我有一些额外的GUI更新,这些更新不是外部方法的一部分,所以我需要为每个方法调用一个,因为你说我不能调用SerialPort.DataReceived:我无法避免对额外代码部分的多次调用,我必须将其包装并放入另一个方法中…顺便说一句,我不明白为什么要这样做。InvokeRequired:它检查调用方是否必须使用Invoke方法来执行对控件的方法调用,但由于我确信我所有的控件都是在与我调用的线程不同的线程中创建的,因此它肯定总是正确的。