编写扩展方法来调用控件的更好方法是什么?
我有这个通用函数来调用WinForm控件:
public static void Invoke(this Control c, Action action) { if (c.InvokeRequired) c.TopLevelControl.Invoke(action); else action(); }
我正在考虑通过采用更严厉的限制来防止无意义的事情,使其变得更好,可能是这样的:
button1.Invoke(() => list.Add(1));
还可以进行冗余打字,例如:
button1.Invoke(() => button1.Hide());
因为我们已经指定this
是button1
。
所以我做到了:
public static void Invoke(this T c, Action action) where T : Control { if (c.InvokeRequired) c.TopLevelControl.Invoke(action); else action(c); }
现在我要打电话,
button1.Invoke((c) => c.Hide());
要么
button1.Invoke((c) => button1.Hide());
现在我觉得即便如此,还有一些不仅仅是需要打字。 如果我指定this
是button1
,那么在lambda表达式中我不想再指定一个虚拟变量c
来告诉操作的位置。 无论如何我可以再缩短一下吗? 也许就像
button1.Invoke(Hide);
要么
button1.Hide.Invoke();
在C#中左右?
首先让我说你可能会过度思考这个问题 – 短代码是一件很棒的事情,但是对于任何试图阅读代码的人而言,它都会让人感到困惑。
现在,你的第一个建议是:
button1.Invoke(Hide);
可以工作,如果你做到:
button1.Invoke(button1.Hide);
因为否则编译器无法知道,在哪里查找方法Hide()。 它甚至可能导致一些奇怪的行为,例如,如果所有这些代码都在某个派生类中,如下所示:
class A : Control { public A() { Button button1=new Button(); button1.Invoke(Hide); } }
现在它会编译,但Hide()方法将是整个控件的Hide()方法,而不是按钮! 实现这一目标的方法很简单:
public static void Invoke(this Control c, Action action) { c.Invoke(action); }
后一种方式:
button1.Hide().Invoke();
即使没有添加扩展方法也能工作,你只需要做到:
((Action)button1.Hide).Invoke();
这当然意味着在当前线程中调用Hide()方法,这可能不是你想要的。 所以做到:
((Action)button1.Hide).Invoke(button1); public static void Invoke(this Action action, Control c) { c.Invoke(action); }
很抱歉很长的答案,希望它有所帮助。
为了建立其他答案,我会把它放到一个单独的扩展类中。
public static void Invoke(this T c, Action action) where T : Control { if (c.InvokeRequired) c.Invoke(new Action>(Invoke), new object[] { c, action }); else action(c); }
这将防止在交叉线程时抛出TargetParameterCountException
。
致电:
button1.Invoke(x => x.Hide());
您可以使用SynchronizationContext.Post或SynchronizationContext.Send使框架将操作封送到UI线程,无论是Windows窗体还是WPF。 静态SynchronizationContext.Current方法将为您的应用程序类型返回适当的同步上下文。
Post发送阻止时异步执行,直到操作完成。
以下代码将异步隐藏按钮:
SynchronizationContext.Current.Post(_=>button1.Hide(),null);
我会选择:
public static void Invoke(this T c, Action action) where T : Control { if (c.InvokeRequired) c.TopLevelControl.Invoke(action); else action(c); }
和
button.Invoke(c => c.Hide());
它是最干净的(你最初指定的按钮执行操作)和最安全的(你不必指定button1
两次……它作为你的lambda的参数返回给你)。 我相信这是优雅的语法。
它肯定不能像button1.Invoke(Hide);
或button1.Hide.Invoke();
因为C#语法限制。
但是如果你愿意放弃IntelliSense,你可以缩短它。 作为缺点,在编译时通常可以检测和修复的一些错误(如拼写错误或不匹配参数)将成为运行时错误。 有时它是可以接受的,有时它不是。
outlook未来,这是一个示例用法 :
button1.Invoke("Hide");
要么
button1.Invoke("ResumeLayout", true);
解:
上述就是C#学习教程:编写扩展方法来调用控件的更好方法是什么?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
internal static class ExtensionMethods { internal static object Invoke(this TControl control, string methodName, params object[] parameters) where TControl : Control { object result; if (control == null) throw new ArgumentNullException("control"); if (string.IsNullOrEmpty(methodName)) throw new ArgumentNullException("methodName"); if (control.InvokeRequired) result = control.Invoke(new MethodInvoker(() => Invoke(control, methodName, parameters))); else { MethodInfo mi = null; if (parameters != null && parameters.Length > 0) { Type[] types = new Type[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { if (parameters[i] != null) types[i] = parameters[i].GetType(); } mi = control.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public, null, types, null); } else mi = control.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public); if (mi == null) throw new InvalidOperationException(methodName); result = mi.Invoke(control, parameters); } return result; }
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1017051.html