无法将调用用于特定控件

时间:2019-07-08 06:49:18

标签: c# winforms

我想创建一个禁用整个UserControl的方法。但是,如果我禁用了整个布局,那似乎就很糟糕(禁用的网格,标签看上去是如此灰暗)。因此,我决定在布局中捕获控件并手动禁用它们。但是仅当我禁用控件的布局时才调用方法。如何在UserControls中使用此方法?

   public static void Enable(this Control con, bool isEnable)
            {
                if (con != null)
                {
                        foreach (Control ctrl in con.Controls)
                        {    
                            var a = ctrl.GetType().Name;
                            var b = ctrl.Name;

                            if (ctrl is TfSearchButton)
                            {
                                ctrl.Enabled = isEnable;
                                ctrl.Invoke((MethodInvoker)(() => ctrl.Enabled = isEnable));
                            }
                            if (ctrl is TfNumericEdit)
                            {
                                ctrl.Enabled = isEnable;
                                ctrl.Invoke((MethodInvoker)(() => ctrl.Enabled = isEnable));
                            }
                            if (ctrl is TfCheckEdit)
                            {
                                ctrl.Enabled = isEnable;
                                ctrl.Invoke((MethodInvoker)(() => ctrl.Enabled = isEnable));
                            }
                            if (ctrl is TfComboEdit)
                            {
                                ctrl.Enabled = isEnable;
                                //ctrl.Invoke((MethodInvoker)(() => ctrl.Enabled = isEnable));
                            }
                            if (ctrl is TfTextEdit)
                            {
                                ctrl.Enabled = isEnable;
                                ctrl.Invoke((MethodInvoker)(() => ctrl.Enabled = isEnable));
                            }
                            if (ctrl is TfRadioGroup)
                            {
                                ctrl.Enabled = isEnable;
                                ctrl.Invoke((MethodInvoker)(() => ctrl.Enabled = isEnable));
                            }
                            if (ctrl is TfDateEdit)
                            {
                                ctrl.Enabled = isEnable;
                                ctrl.Invoke((MethodInvoker)(() => ctrl.Enabled = isEnable));
                            }
                            if (ctrl is TfLookUpEdit)
                            {
                                ctrl.Enabled = isEnable;
                                ctrl.Invoke((MethodInvoker)(() => ctrl.Enabled = isEnable));
                            }
                            if (ctrl is TfGrid)
                            {
                                GridView view = ((TfGrid)ctrl).MainView as GridView;
                                view.OptionsBehavior.Editable = isEnable;
                                ctrl.Invoke((MethodInvoker)(() => view.OptionsBehavior.Editable = isEnable));
                            }
                            if (ctrl.GetType().BaseType.Name is "TfControlBase" || ctrl is TfLayoutControl)
                            {
                                Enable(ctrl, isEnable);
                            }

                        }
                }
            }

1 个答案:

答案 0 :(得分:1)

我发现的一个问题是,您既可以使用Invoke也可以使用Invoke来访问控件。

ctrl.Enabled = isEnable;
ctrl.Invoke((MethodInvoker)(() => ctrl.Enabled = isEnable));

由于Invoke是必需的,因为我们必须仅从创建它的线程访问控制句柄,并且如果我们不确定是否在该线程上运行,则必须使用InvokeRequired和如果返回true,则必须使用Invoke

要涵盖这两种情况,我们可以将代码分解如下:

private static void InvokeControl(Control ctrl, Action<Control> action)
{
    if (ctrl.InvokeRequired)
    {
        ctrl.Invoke(() => action(ctrl));
    }
    else
    {
        action(ctrl);
    }
}

public static void Enable(this Control con, bool isEnable)
{
    if (con == null)
    {
        return;
    }
    foreach (Control ctrl in con.Controls)
    {    
        if (ctrl is TfSearchButton)
        {
            InvokeControl(ctrl, c => c.Enabled = isEnable);
        }
        //... implement the rest of the cases in similar way
    }
}

更新

请多加考虑,从逻辑上讲,在这种情况下,切换多个控件的启用状态是原子操作。在上面我建议的解决方案中,一次调用Enable()会导致大量上下文切换和线程阻塞。为了使Enable()操作在技术上“更原子”,最好在UI线程上完全运行Enable()

public static void Enable(this Control con, bool isEnable)
{
    if (con == null)
    {
        return;
    }

    if (con.InvokeRequired) // returns false if we're on the UI thread
    {
        // if we're not on the UI thread, enqueue a new call to Enable()
        // the call will be dequeued and executed by the UI thread
        con.BeginInvoke(() => Enable(con, isEnable));
        return; 
    }

    // if we got to this point, we're running on the UI thread

    foreach (Control ctrl in con.Controls)
    {    
        // since this code always runs on UI thread,
        // there is no need to use Invoke/BeginInvoke

        if (ctrl is TfSearchButton)
        {
            ctrl.Enabled = isEnable;
        }
        // ... the rest of the cases ...
    }
}