首页 > 解决方案 > 将 windows.forms 控件保留在同一个主线程中

问题描述

所以,我有一个调用方法的获胜表格

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,我该如何防止它启动一个新线程并继续使用主线程?

我查看了 singlethreadsynchronizationcontext,但无法编译,我知道您可以调用:

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

但是我有很多属性变化的控件,必须有一种方法可以将 UI 保持在主线程上吗?

标签: c#multithreadingwinforms

解决方案


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

注释中提到的一种选择是使用async/await,其中关键字 after 的部分方法在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";
}

推荐阅读