在单独的线程上打开一个新的窗体对话框
本文关键字:一个 窗体 对话框 线程 单独 | 更新日期: 2023-09-27 18:28:59
我有一个对象运行它自己的线程,处理来自网络摄像头的输入并更新窗口控件。在它的操作过程中,用户可能会指示他们希望校准应用程序,我基本上希望当前线程挂起,在它自己的线程中打开一个新的Form,让用户执行他们的inut并单击"确定",然后这个临时线程终止,原始线程恢复。我的校准表格看起来像
//Constructor() {}
public void StartCalibration() {
Debug.WriteLine("StartCalibration CALLED!");
var thread = new Thread(Run);
thread.Start();
}
private void Run() {
while (!finished) {
//process user input
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
Graphics g = e.Graphics;
if (image != null)
g.DrawImage(image, new Point(15, 15));
}
在原始对象线程中,我有以下
public void Run() {
if (calibrate == true) {
CalibrationForm calibrationForm = new CalibrationForm(source);
if (calibrationForm.InvokeRequired)
calibrationForm.Invoke(new MethodInvoker(calibrationForm.StartCalibration));
else
calibrationForm.StartCalibration();
if (calibrationForm.ShowDialog() == DialogResult.OK)
//get data from calibrationForm
calibrationForm.Dispose();
}
//continue with this threads operation
看起来对ShowDialog()的调用仍然抛出一个异常
跨线程操作无效:已访问控件"CalibrationForm"从上创建的线程以外的线程
因此,我目前想知道我的最佳选择是尝试简单地挂起我当前的线程,等待校准表单完成后再尝试加入,还是有更好的方法来实现我的目标?
在WinForms中,所有UI元素都必须从主线程访问。
您可以对其他线程进行后台处理(例如从远程源检索数据或日志记录),但不能创建或修改UI元素。
正如其他人所说,只有主UI线程才能与UI组件交互。
要从其他线程与UI交互,您有两个选项。您可以对窗体/控件调用Control.Invoke或Control.BeginInvoke,也可以使用WindowsFormsSynchronizationContext。WindowsFormsSynchronizationContext 示例
您需要在UI线程上运行所有与UI交互的代码。这是WinForms的硬性规定。
如果您需要从线程中显示UI或与现有UI交互,请调用Invoke或BeginInvoke,具体取决于您想要同步操作还是异步操作。这些方法将在UI线程上执行UI代码。
所以我最终完成了这项工作,我的主要问题主要是让我的第二个表单运行它自己的任务,的行为就像一个标准的对话框窗口。
public partial class CalibrationForm : Form {
public CalibrationForm(ISource source) {
InitializeComponent();
this.source = source;
//other setup
}
private void Run() {
while (!finished) {
//process user input
this.Invalidate();
if (this.InvokeRequired)
this.BeginInvoke(new MethodInvoker(Update));
else
Update();
}
}
private void OKButton_Click(object sender, EventArgs e) {
finished = true;
}
然后在调用线程中。。。
CalibrationForm calibrationForm = new CalibrationForm(camera);
new Thread(calibrationForm.Run).Start();
if (calibrationForm.ShowDialog(this) == DialogResult.OK)
//get data from calibrationForm
最后一件事是确保为窗体上的按钮设置DialogResult属性,以便它们向ShowDialog()
调用返回适当的值。