【问题标题】:How to add an event to a UserControl in C#?如何在 C# 中向 UserControl 添加事件?
【发布时间】:2010-08-15 05:51:56
【问题描述】:

我有一个包含 3 个标签的 UserControl。我想为其添加一个事件,当其中一个标签的文本发生更改时会发生该事件。
我正在使用 Visual Studio 2010

【问题讨论】:

  • 您使用的是 Winforms 还是 WPF?
  • 不知道,我用的是UserControl,但不是WPF

标签: c# winforms events user-controls


【解决方案1】:

首先,您需要在您的类中声明事件(连同您的方法和构造函数):

public event EventHandler LabelsTextChanged;

然后您需要创建一个方法来处理各个标签的TextChanged 事件。

private void HandleLabelTextChanged(object sender, EventArgs e)
{
    // we'll explain this in a minute
    this.OnLabelsTextChanged(EventArgs.Empty);
}

某处,可能在您控件的构造函数中,您需要订阅标签的TextChanged 事件。

myLabel1.TextChanged += this.HandleLabelTextChanged;
myLabel2.TextChanged += this.HandleLabelTextChanged;
myLabel3.TextChanged += this.HandleLabelTextChanged;

现在是HandleLabelsTextChanged 方法。我们可以直接加注LabelsTextChanged;但是,.NET 框架设计指南说创建OnEventName 受保护的虚拟方法来为我们引发事件是最佳实践。这样,继承类可以通过重写OnEventName 方法来“处理”事件,结果证明这比订阅事件有更好的性能。即使您认为自己永远不会覆盖 OnEventName 方法,但还是养成这样做的习惯是个好主意,因为它可以简化事件引发过程。

这是我们的OnLabelsTextChanged

protected virtual void OnLabelsTextChanged(EventArgs e)
{
    EventHandler handler = this.LabelsTextChanged;
    if (handler != null)
    {
        handler(this, e);
    }
}

我们必须检查 null,因为没有订阅者的事件是 null。如果我们试图引发一个空事件,我们会得到一个NullReferenceException。请注意,我们将事件的EventHandler 复制到一个局部变量,然后再检查它是否为空并引发事件。如果我们改为这样做:

if (this.LabelsTextChanged != null)
{
    this.LabelsTextChanged(this, e);
}

我们将在无效性检查和事件引发之间存在竞争条件。如果碰巧事件的订阅者在我们引发事件之前但在我们检查 null 之后取消订阅,则会引发异常。您通常不会遇到此问题,但最好养成以安全方式编写它的习惯。

编辑:下面是public event EventHandler LabelsTextChanged; 行的放置方式:

namespace YourNamespace
{
    class MyUserControl : UserControl
    {
        // it needs to be here:
        public event EventHandler LabelsTextChanged;

        ...
    }
}

Here是事件设计的框架设计指南,供进一步阅读。

【讨论】:

  • 你的想法也有同样的问题,编译器说:
    “预期的类、委托、枚举、接口或结构”
    在第一行它有一个与事件有关的问题
  • @saeed:你把public event EventHandler LabelsTextChanged;放在哪里?它必须在您的类内部(而不是在方法内部或类定义外部)。
  • @ZachJohnson 很有帮助!继承的东西是否需要“this”关键字,还是在这种情况下是可选的?
  • 你可以缩短你的空检查this.ElementChanged?.Invoke(this, e);
【解决方案2】:

首先你应该在你的用户控件中声明一个事件,例如:

public event EventHandler TextOfLabelChanged;

那么你必须在运行时调用绑定到你的事件(如果有的话)的回调函数。你可以通过处理这样的标签的 TextChanged 事件来做到这一点:

public void LabelTextChanged(object sender,EventArgs e)
{
if(TextOfLabelChanged!=null)
TextOfLabelChanged(sender,e);
}

如果你愿意,你可以拥有自己的 EventArgs 对象。

您应该在代码中的某处将标签 TextChanged 事件绑定到此方法,如下所示:

_myLabel.TextChanged+=LabelTextChanged;

【讨论】:

  • 为什么要使用“if(TextOfLabelChanged!=null)”?
  • 它有一个编译错误,第一行写着:“Expected class, delegate, enum, interface, or struct”
  • @saeed:我们必须检查 null 因为没有订阅者的事件是 null。如果我们试图引发一个空事件,我们会得到一个NullReferenceException
  • tnx,编译报错怎么办?
【解决方案3】:
public delegate void TextChangedEventHandler(object sender, EventArgs e);
public event TextChangedEventHandler LabelTextChanged;

// ...

protected void MyTextBox_TextChanged(object sender, EventArgs e)
{
    if (LabelTextChanged != null) {
        LabelTextChanged(this, e);
    }
}

【讨论】:

  • 它有一个编译错误,第二行显示:“Expected class, delegate, enum, interface, or struct”它似乎与“event”有问题
【解决方案4】:

编译错误,第二行显示“预期的类、委托、枚举、接口或结构”似乎与“事件...”有问题


这两行需要在类声明中。

public delegate void TextChangedEventHandler(object sender, EventArgs e);
public event TextChangedEventHandler LabelTextChanged;

【讨论】:

    【解决方案5】:

    有一个非常简单的方法可以做到这一点!

    在用户控件表单上:

    1. 将属性更改为公共以在任何地方访问

    在您使用 UserControl 的主窗体上:

    .5:在using 区域添加using userControl1=UserControl.userControl1

    1.将'Laod'事件添加到您的用户控件:

    this.userControl1.Load += new System.EventHandler(this.userControl1_Load);
    

    2.在 userControl1_Load 中:

    private void userControl1_Load(object sender, EventArgs e)
    {
         (sender as UserControl1).label1.TextChanged += label1_TextChanged; 
         //add a 'TextChanged' event to the label1 of UserControl1 
         OR use direct cast:
         ((UserControl1) sender).label1.TextChanged += label1_TextChanged;
    
    }
    

    3.在标签1_TextChanged中:

     private void label1_TextChanged(object sender, EventArgs e)
     {
         //do whatever you want
     }
    

    【讨论】:

      【解决方案6】:

      您必须在Namespace 中声明eventdelegate。尝试将代码置于class 范围内。它会运行良好。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-17
        • 1970-01-01
        • 2016-05-31
        • 1970-01-01
        • 2023-03-30
        • 1970-01-01
        相关资源
        最近更新 更多