我在这里为其他程序员编写了几个UserControl。
一些与基本名称相同的暴露事件处理程序被接受
(UserControl CodesCombo -> SelectedValueChanged)
有些不是
(UserControl TextBox -> TextChanged)
我正在编写一个包含文本框的UserControl。我需要向该控件的潜在使用者公开TextChanged事件。
我有一个基于ComboBox的类似控件,并且我使用了
public event EventHandler SelectedValueChanged
{
add { cbMain.SelectedValueChanged += value; }
remove { cbMain.SelectedValueChanged -= value; }
}
公开“更改”事件“ SelectedValueChanged”,它的工作没有任何问题。
但是,当我尝试以类似方式在基于TextBox的控件中使用此技术时
public event EventHandler TextChanged
{
add { tbMain.TextChanged += value; }
remove { tbMain.TextChanged -= value; }
}
我收到警告消息:
'MyTextBox.TextChanged' hides inherited member 'UserControl.TextChanged'. Use new keyword if hiding was intentional.
除了显而易见的内容外,我不确定消息的含义,但是我知道的是我不-想想-我想隐藏任何东西。我有内部的SelectedValueChanged和TextChanged函数(cbMain_SelectedValueChanged,tbMain_TextChanged),这些函数可以满足我的一些需要,但我想允许消费者也可以对文本更改进行事件调用,就像在基于ComboBox的事件中一样。>
此外,在测试程序的可用事件列表中,我根本没有任何“更改”事件。
我现在通过将事件公开为“ TextChange”来解决了这个问题
new public event EventHandler TextChange
{
add { tbMain.TextChanged += value; }
remove { tbMain.TextChanged -= value; }
}
这给了我列表中的一个事件,并且看起来似乎运行良好,但是我希望对此有一个通用的解决方案,因为我们正在为这些程序包制作更多的控件,我不认为我可以不用名字“ off”。
您知道此消息实际上是在告诉我什么,以及如何在内部获取我的活动,同时仍然让用户获得他们的信息吗?
谢谢!
更新:要求提供更具体的代码:
namespace NCFLSToolbox
{
public partial class NCFLSCodesCombo : UserControl
{
//Listed in the Events for System.Windows.Forms.ComboBox
private void cbMain_SelectedValueChanged(object sender, EventArgs e)
{
ControlRequiredColoring();
}
//Exposed Event for user
public event EventHandler SelectedValueChanged
{
add { cbMain.SelectedValueChanged += value; }
remove { cbMain.SelectedValueChanged -= value; }
}
}
public partial class NCFLSTextbox : UserControl
{
//Listed in the Events for System.Windows.Forms.TextBox
private void tbMain_TextChanged(object sender, EventArgs e)
{
ControlRequiredColoring();
}
//Couldn't expose "TextChanged" by name...
////public event EventHandler TextChanged
//// {
//// add { tbMain.TextChanged += value; }
//// remove { tbMain.TextChanged -= value; }
//// }
//...so I exposed "TextChange" instead.
public event EventHandler TextChange
{
add { tbMain.TextChanged += value; }
remove { tbMain.TextChanged -= value; }
}
}
}
答案 0 :(得分:5)
您知道这条消息真正告诉我什么吗?
首先,了解隐藏的含义。暂时忘记这是一个事件。如果我们有:
class B { public void M() { Console.WriteLine("B.M()"); } }
class D : B { public void M() { Console.WriteLine("D.M()"); } }
然后我们有两个方法都称为M。如果您说:
D d = new D();
B b = d;
d.M(); // D.M();
b.M(); // B.M();
编译器警告您有两种方法,而不是一种,而哪种方法取决于接收方的编译时类型, NOT 接收方的运行时类型。
为什么可能不是您想要的?
三个原因。
首先,许多C#程序员从Java进入C#,在Java中,方法被自动覆盖。在C#中,必须重写virtual
方法。编译器告诉您您没有获得预期的语义。
第二,这是为了缓解脆性基类问题。假设B的作者为D团队提供了一个包含B且没有M的DLL程序集,D派生了D,并添加了方法D.M。然后B团队意识到他们可以实现M,因此他们将其添加到B并为D团队提供了一个新的程序集。现在应该警告D团队B.M存在,以便他们可以决定是否删除D.M。
第三,为什么首先要这样做?如果基类已经具有所需的事件,请使用它!不要用旧的来做新的。只需使用旧的。编译器告诉您,您肯定在做奇怪的事情,并且可能是错误的。
如果打算在两个不同的类上有两个成员,而一个成员隐藏另一个成员,则可以通过在该成员上放置new
来告诉编译器“我已经考虑过这一点,这是有意的”。那就是“这是一个新成员,我的意思是使其成为新成员,而不是替代旧成员。”
答案 1 :(得分:1)
问题在于TextBox事件不会传播到父用户控件。如果您希望他们这样做,有两种方法可以实现:
1)让用户控件上的事件将事件处理程序的所有附加/删除操作转移到UserControl
的事件处理程序中。这大致就是您的问题正在尝试做的事情。但是,我不建议这样做。
2)在父用户控件上的TextBox
触发事件上触发事件。
因此,只需在InitializeComponent()
下的构造函数中运行以下代码:
tbMain.TextChanged += (sender,e)=>OnTextChanged(e);
使用这种方法,TextBox
中的TextChanged事件将调用OnTextChanged
,这将引发一个TextChanged
事件。您不能直接调用基类事件(因此提供了OnTextChanged
方法的原因)。
编辑: tbMain.TextChanged += (sender,e)=>OnTextChanged(e);
在语义上等效于以下代码:
tbMain.TextChanged += OnTbMainTextChanged;
...
} //End of Constructor
private void OnTbMainTextChanged(object sender, EventArgs e)
{
OnTextChanged(e);
}
使用lambda函数的好处是它更加独立。除其他优点外,使用独立的lambda函数对于将来的代码维护人员来说很明显sender
没有被传播,而无需维护人员导航到指定的方法。这就是您想要的:从订阅者到用户控件的角度来看,使用TextBox来实现控件是一种实现细节。