【问题标题】:How to clone Control event handlers at run time?如何在运行时克隆 Control 事件处理程序?
【发布时间】:2011-05-19 07:10:27
【问题描述】:

我想复制一个控件,如 Button、TextBox 等。 但我不知道如何将事件处理程序方法(如Click)复制到新控件。

我现在有以下代码:

var btn2 = new Button();  
btn2.Text = btn1.Text;
btn2.size = btn1.size;
// ...
btn2.Click ??? btn1.Click

还有其他方法可以复制控件吗?

【问题讨论】:

  • 不确定为什么要复制,但简单的复制过去会创建控件的新实例。
  • 您想在运行时创建一个假设按钮的副本吗?与前一个按钮的事件处理程序相同?

标签: c# .net winforms controls event-handling


【解决方案1】:

克隆任何 WinForms 控件的所有事件:

var eventsField = typeof(Component).GetField("events", BindingFlags.NonPublic | BindingFlags.Instance);
var eventHandlerList = eventsField.GetValue(button1);
eventsField.SetValue(button2, eventHandlerList);

【讨论】:

  • 嗯,也许吧。但这是否记录在某处? “事件”是否保证永远是该字段的名称?此外,看起来类似于解决方案here
  • @Cody - 它适用于 .NET 2、3.5 和 4。它以后会起作用 - 没人知道。是黑客吗?是的。
  • 提醒任何想要这样做的人。 Component 类中的 events 字段是一个 EventHandlerList。您在这里所做的只是复制引用(指向其在内存中位置的指针),以便两个组件现在共享同一个列表。每当您修改任一组件中的任何事件(您从中复制的事件或复制到的事件)的事件处理程序列表时,您都在修改两者的事件处理程序列表。请注意这一点,并确保这是您想要做的,并且不会给您带来任何问题。我会小心地将其称为“克隆”。它更像是“分享”。
  • 我尝试使用它自动将ToolStripMenuItem 的子项重新创建为ContextMenu 子项以用作右键菜单,但使用它从ToolStripMenuItem 复制侦听器对象放入新的MenuItem 没有效果。
【解决方案2】:

您只需要add the event handler 方法为新的按钮控件。 C# 使用 += 运算符来执行此操作。所以你可以简单地写:

btn2.Click += btn1_Click

另外,一个更强大的方法是use reflection。这里特别有用的是EventInfo.AddEventHandler method

【讨论】:

  • 但是我想要重复控制,我不知道“btn1_Click”功能
  • @mrbm:正如我在对 Vimvq1987 答案的评论中提到的,如果您在运行时不知道事件处理程序方法的名称,则需要使用反射。它有点复杂,但功能更强大。我提供的链接有完整的示例代码。
【解决方案3】:

如果您只是想复制最终将呈现的 HTML 元素(包括附加的事件处理程序),您可以使用以下扩展方法来输出 HTML 的副本。

/// <summary>
/// Render Control to HTML as string
/// </summary>
public static string Render(this System.Web.UI.Control control)
{
    var sb = new StringBuilder();
    System.IO.StringWriter stWriter = new System.IO.StringWriter(sb);
    System.Web.UI.HtmlTextWriter htmlWriter = new System.Web.UI.HtmlTextWriter(stWriter);
    control.RenderControl(htmlWriter);
    return sb.ToString();
}

然后您可以使用它在 aspx 标记中输出一个副本,如下所示:

<%= btn1.Render() %>

如果你想修改副本上的文本,你可以在渲染的 html 上做一个字符串替换,或者你可以在原始按钮上设置文本,并在 Render 调用后重置它asx,即:

<% btn1.Text = "Text for original button"; %>

【讨论】:

    【解决方案4】:

    我没有正确理解你的问题。您可以像这样将一个事件附加到多个控件。

    Button1.Click += button_click;
    Button2.Click += button_click;
    

    【讨论】:

    • 是的,我现在,假设我不知道“button_click”函数,我只有 Button1,我想获得链接到 Click 事件的函数。
    • 那我觉得你需要调用 Button.PerformClick() 方法。它将执行相关的点击事件。
    • 不错不错,但是不能直接使用,btn2.Click += new EventHandler(btn1.PerformClick);错误>>“PerformClick”没有重载匹配委托“System.EventHandler”
    • 我也可以用这个代码,btn2.Click += (ss,ee)=>{btn1.PerformClick();};
    【解决方案5】:

    更好的方法是使用组件类并将控件继承到该类

    public class DuplicateButton : OrginalButton
    {
    
    }
    

    您可以在部分类中进行更改,因此无需创建事件

    【讨论】:

    • 我不这么认为。事件附加到按钮的实例,而不是类本身。在这种情况下,继承不起作用
    • 我想复制一个控件而不是一个类!
    • 这和问题有什么关系?
    • 事件附加到一个实例,而不是类!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-26
    • 1970-01-01
    • 1970-01-01
    • 2016-03-22
    • 1970-01-01
    • 2010-12-27
    • 1970-01-01
    相关资源
    最近更新 更多