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

时间:2012-03-26 15:10:28

标签: c# winforms multithreading

我有一个对象运行它自己的线程,处理来自网络摄像头的输入并更新窗口Control。在它的操作过程中,用户可能会指示他们希望校准应用程序,我本来希望将当前线程挂起,在自己的线程中打开一个新表单,让用户执行他们的inut并单击OK,然后这个临时线程死掉,原始简历。我的校准表格看起来像

    //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'   来自其在

上创建的线程以外的线程

所以我现在想知道我最好的选择是尝试简单地暂停当前线程并等到校准表单完成尝试加入,还是有更好的方法来实现我的目标?

4 个答案:

答案 0 :(得分:2)

在WinForms中,必须从主线程访问所有UI元素。

您可以对其他线程进行后台处理(例如从远程源检索数据或进行日志记录),但不能创建或修改UI元素。

答案 1 :(得分:1)

正如其他人所说,只有主UI线程可以与UI组件交互。

要从其他线程与UI进行交互,您有2个选项。您可以在窗体/控件上调用Control.Invoke或Control.BeginInvoke,也可以使用WindowsFormsSynchronizationContext。 Example of WindowsFormsSynchronizationContext

答案 2 :(得分:0)

您需要在UI线程上运行与UI交互的所有代码。这是WinForms的一个难点。

如果需要从线程显示UI或与现有UI交互,请调用Invoke或BeginInvoke,具体取决于您是要进行同步操作还是异步操作。这些方法将在UI线程上执行UI代码。

答案 3 :(得分:0)

所以我最终得到了这个,我的主要问题主要是让我的第二个表单运行它自己的任务表现得像一个标准的对话窗口。

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()调用。