在单独的线程上打开一个新的窗体对话框

本文关键字:一个 窗体 对话框 线程 单独 | 更新日期: 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()调用返回适当的值。