我想创建一个禁用整个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);
}
}
}
}
答案 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 ...
}
}