编写扩展方法来调用控件的更好方法是什么?

我有这个通用函数来调用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()); 

因为我们已经指定thisbutton1

所以我做到了:

 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()); 

现在我觉得即便如此,还有一些不仅仅是需要打字。 如果我指定thisbutton1 ,那么在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); 

解:

 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; }