【问题标题】:Overriden event not being called in user control用户控件中未调用覆盖事件
【发布时间】:2019-02-10 03:23:29
【问题描述】:

我有一个带有TextBox 的用户控件:

public partial class MyControl : UserControl
{
    public new event CancelEventHandler Validating
    {
        add
        {
            txt.Validating += value;
        }
        remove
        {
            txt.Validating -= value;
        }
    }

    public new string Text
    {
        get => txt.Text;
        set => txt.Text = value;
    }
}

我将控件和ErrorProvider 放在表单上并执行以下操作:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        SetErrorEvents(myControl1);
    }

    private void SetErrorEvents(object control)
    {
        (control as Control).Validating += ValidationEvent;
    }

    private void ValidationEvent(object sender, CancelEventArgs e)
    {
        var control = (Control)sender;

        if (string.IsNullOrWhiteSpace(control.Text))
            errorProvider1.SetError(control, "error");
        else
            errorProvider1.SetError(control, string.Empty);
    }
}

为我的控件的Validating 事件设置委托时,它是为UserControl 本身设置委托,而不是被覆盖,以便设置TextBox 的事件。

不应该按原样工作吗?我错过了什么?

【问题讨论】:

  • 它没有被覆盖,它是新的。
  • @RezaAghaei 我只能设置新的,因为该事件不是虚拟的。如果我这样做 (control as MyControl).Validating += ValidationEvent; 它可以工作,但我不能这样做,因为它是一种接受其他类型控件的方法。

标签: c# .net winforms events user-controls


【解决方案1】:

它没有被覆盖,它被new 关键字隐藏或隐藏。你还没有订阅新事件,你已经订阅了基类事件。这基本上就是polymorphism 的工作原理。

  • 如果要在子控件验证时引发用户控件的Validating 事件,请处理子控件的Validating 事件并调用用户控件的OnValidating 方法。

  • 如果你想覆盖Validating事件覆盖OnValidating方法。

  • 如果你想改变Validating事件的发送者,你需要改变Validating事件被调用的方式。为此,您需要使用反射并找到事件并自己直接调用它。

示例 - 当子控件正在验证时引发 UserControl 的验证事件

如果您想在子文本框验证时引发控件的Validating 事件,请处理子控件的Validating 事件并调用``

public MyControl()
{
    InitializeComponent();
    txt.Validating += (obj, args) => OnValidating(args);
}

示例 - 覆盖验证事件

protected override void OnValidating(CancelEventArgs e)
{       
    // Add custom code here.       
    base.OnValidating(e);
}

示例 - 手动引发 Validating 事件而不调用 base.OnValidating

如果由于某种原因你不想调用base.OnValidating,而它的职责基本上是引发Validating事件,你可以找到该事件并直接调用它:

protected override void OnValidating(CancelEventArgs e)
{  
    var f = typeof(Control).GetField("EventValidating",
            System.Reflection.BindingFlags.NonPublic |
            System.Reflection.BindingFlags.Static);
    var validating = (CancelEventHandler)Events[f.GetValue(this)];
    validating?.Invoke(this, e); 
}

这样做,例如您可以设置另一个发件人,例如子控件,而不是this

【讨论】:

  • 感谢您提供详细信息。但是,这并不能解决我的问题。我必须设置Validating 委托,而不是为UserControl 本身设置一个,我需要设置它的TextBox
  • @Ivan-MarkDebono 我相信答案包含解决问题所需的所有信息。例如,如果您希望 ValidationEvent 接收 txt 作为 sender 并且错误提供程序在 txt 附近显示错误而不是用户控件,则混合示例 1 和示例 3 并在示例 3 中提高使用validating?.Invoke(txt, e); 的事件这样您就可以使用您的通用代码来订阅事件。它总是在 txt 正在验证并且发送者是 txt 时引发事件,而您订阅了 usercontrol'a 验证事件。
【解决方案2】:

定义这个接口:

public interface IMyControl
{
    event CancelEventHandler Validating;
}

将界面应用于您的自定义控件:

public partial class MyControl : UserControl, IMyControl
{
    ...
}

在您的 Form 类中,更新 SetErrorEvents() 使其转换为 IMyControl

...
private void SetErrorEvents(object control)
{
    (control as IMyControl).Validating += ValidationEvent;
}
...

【讨论】:

  • 我需要保持这个方法“通用”,因为它处理不同类型的控件。
  • @Ivan-MarkDebono,没问题,请查看我更新的答案;您需要将该接口应用于需要该行为的控件。
猜你喜欢
  • 2012-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多