将windows.forms控件保留在同一主线程中

时间:2018-10-04 15:39:28

标签: c# multithreading winforms

所以,我有一个叫方法的胜利形式

dvm.SetVoltage(excitationVoltage, rigNo);

在另一个类中运行任务

public void SetVoltage(double voltage, int rigNum)
{
    Task.Run(() => ReadDVMWorker());
}

工作人员完成操作(设置电压)后,将在主Form1.cs中触发一个事件

private void dvmVoltageSet(object sender, VoltageEventArgs e)
{
    VoltageSet = e.VolSet;
    TestLvdtNull();
}

调用TestLvdtNull方法:

private void TestLvdtNull()
{
     tbMessage.Location = new Point((int)(x / 2 - 250), 150);
}

一旦到达tbMessage行,由于它启动了另一个线程而不是在其中创建的tbMessage,它会引发异常,如何防止它启动新线程并继续使用Main线程?

我查看了单线程同步上下文,但是无法对其进行编译,我知道您可以调用:

tbMessage.Invoke((Action)delegate
{
    tbMessage.Location = new Point((int)(x / 2 - 250), 150);
});

但是我有许多控件,它们的许多属性都在变化,必须有一种方法将UI保留在主线程上吗?

3 个答案:

答案 0 :(得分:1)

所有UI控件都在一个线程中创建。这是设计使然的许多UI框架。完成任务后,您必须返回UI线程以访问UI控件。

注释中提到的一个选项是使用 async / await ,其中await关键字之后的方法的一部分与async方法之前的相同的线程上执行。

// UI thread
await ReadDVMWorker(); // executed at ThreadPool
// UI thread

如果您希望继续使用 Task ,则可以将ContinueWith方法与正确的TaskScheduler参数一起使用,以确保您返回到UI线程。例如。 TaskScheduler.FromCurrentSynchronizationContext()

异步/等待尝试代码:

private async void button1_Click(object sender, EventArgs e)
{
    // Call the method that runs asynchronously.
    string result = await WaitAsynchronouslyAsync();

    // Display the result.
    textBox1.Text += result;
}

//The following method runs asynchronously.The UI thread is not
//blocked during the delay.You can move or resize the Form1 window 
//while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync()
{
    await dvm.SetVoltage(5, rigNo); //Task.Delay(10000);
    return "Finished";
}

答案 1 :(得分:0)

您可以使用一种方法来更新任意控件

    private void dvmVoltageSet(object sender, VoltageEventArgs e)
    {
        VoltageSet = e.VolSet;
        TestLvdtNull(tbMessage);
        TestLvdtNull(tbMessage2);
    }

    private void TestLvdtNull(Control control)
    {
        control.BeginInvoke((MethodInvoker)delegate()
            {
                control.Location += new Point((int)(x / 2 - 250), 150);
            });
    }

答案 2 :(得分:0)

尝试了几种不同的方法来解决问题后,我使用SynchronizationContext解决了问题。

这将获取线程的SyncronizationContext:

private SynchronizationContext _synchronizationContext;
SynchronizationContext uiContext = SynchronizationContext.Current;

然后在另一个类中运行我的任务之后,以前在该类中我遇到了跨线程调用异常,然后调用要使用相同UI线程的方法:

uiContext.Post(MethodToCallOnTheSameUIThread, "string");

此后,我可以修改和更新我的文本框和其他控件!

您可以通过以下方式检查线程ID:

int id = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Thread: " + id);

感谢Mike Peretz and his CodeProject