如何从另一个线程调用windows表单属性值?

时间:2017-05-18 10:09:40

标签: c# multithreading winforms properties

我正在尝试关闭一个当前具有外部线程焦点的窗体。问题是我无法通过简单地调用form.Focused来访问该属性,它会按预期抛出“InvalidOperationException:跨线程操作无效”。接下来我尝试在其上调用Invoke但它不能将Control.Focused识别为getter方法。这是当前的代码:

private void CloseFormWithFocus()
{
    FormCollection openForms = Application.OpenForms;
    Form closeThisForm = null;

    foreach (Form f in openForms)
    {
        // Here's the part that does not compile
        if (closeThisForm.Invoke((MethodInvoker)delegate () { closeThisForm.Focused; });)
        {
            closeThisForm = f;
        }
    }
}

然而令我困惑的是,另一个几乎相同的方法是通过与form.Name属性进行比较来关闭表单,这样我就可以像这样简单地调用它(可能不是线程安全的):

private void CloseForm(string formName)
{
    FormCollection openForms = Application.OpenForms;
    Form closeThisForm = null;

    foreach (Form f in openForms)
    {
        if (f.Name == formName)
        {
            closeThisForm = f;                    
        }
    }
}

我已经四处寻找调用属性getter的不同方法,但是所有来源都只是声明编译器应该识别调用表单。聚焦为getter,现在我很难过。

如果form.Propertyname调用不起作用,从外部线程调用(如果可能的话只是简单读取)表单的属性值的正确方法是什么?

谢谢。

1 个答案:

答案 0 :(得分:0)

Focused属性并非“只是一个吸气剂”。

它将当前聚焦窗口与控件的Handle属性进行比较。 Handle属性首先检查跨线程访问 来自源代码:

public virtual bool Focused {
        get {
            return IsHandleCreated && UnsafeNativeMethods.GetFocus() == Handle;
        }
    }

public IntPtr Handle {
        get {
            if (checkForIllegalCrossThreadCalls &&
                !inCrossThreadSafeCall &&
                InvokeRequired) {
                throw new InvalidOperationException(SR.GetString(SR.IllegalCrossThreadCall,
                                                                 Name));
            }

您可以像这样返回Invoke的值:

f.Invoke(new Func<bool>(() => f.Focused))

注意:您使用closeThisForm(虽然为空)而不是f