Невозможно использовать invoke для определенного элемента управления - PullRequest
0 голосов
/ 08 июля 2019

Я хочу создать метод, который отключит весь 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 Ответ

1 голос
/ 08 июля 2019

Одна проблема, которую я нахожу, заключается в том, что вы получаете доступ к элементам управления как без 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() «более атомарной», лучше запускать 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 ...
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...