[英]How do I grab events from sub-controls on a user-control in a WinForms App?
有没有办法让主窗体能够拦截在用户控件上的子控件上触发的事件?
我在应用程序的主窗体中嵌入了一个自定义用户控件。 该控件包含处理数据的各种子控件,这些子控件本身由主窗体上的其他控件显示。 我想要的是当用户更改子控件时是否可以以某种方式通知主窗体,以便我可以在其他地方更新数据和相应的显示。
现在,我在作弊。 我有一个委托连接到子控件的焦点离开事件。 这个委托改变了我没有在其他地方使用的用户控件的一个属性(在这个原因中,CausesValidation)。 然后,当用户控件的 CausesValidation 属性更改时,我在主窗体上定义了一个委托,然后指示应用程序更新数据和显示。
出现问题是因为我还为焦点离开用户控件时设置了一个委托,因为我需要先验证用户控件中的字段,然后才能允许用户执行任何其他操作。 但是,如果用户只是在子控件之间切换,我不想验证,因为它们可能没有完成编辑。
基本上,我希望数据在用户切换子控件或离开用户控件时更新,但不进行验证。 当用户离开控件时,我想更新和验证。 现在,离开用户控件会导致验证触发两次。
最佳做法是在UserControl
上公开事件,将事件冒泡到父窗体。 我已经为你整理了一个例子。 下面是对该示例提供的内容的描述。
UserControl1
TextBox1
创建UserControl
UserControl
上注册一个名为ControlChanged
的公共事件UserControl
为TextBox1
TextChangedEvent 注册一个事件处理程序TextChangeEvent
处理函数中,我调用ControlChanged
事件以冒泡到父窗体Form1
UserControl1
的实例UserControl1
为MouseLeave
和ControlChanged
注册一个事件处理程序这是一个屏幕截图,说明我在UserControl
上定义的ControlChanged
事件可通过父 Windows 窗体上的 Visual Studio 中的 UX 使用。
此类事情的最佳模型是在您的用户控件上创建自定义事件,并在适当的时间引发它们。
您的场景相当复杂,但并非闻所未闻。 (我实际上在我当前的一个项目中处于一种非常相似的模式。)我处理它的方式是用户控件负责它自己的验证。 我不使用 CausesValidation; 相反,在适当的用户控制点,我通过覆盖 ValidateChildren() 执行验证。 (对我来说,这通常发生在用户单击用户控件上的“保存”或“下一步”时。)
不熟悉您的用户控件 UI,这可能不是 100% 适合您的方法。 但是,如果您引发自定义事件(可能使用指定是否执行验证的自定义 EventArgs),您应该能够到达您想要的位置。
您需要在用户控件内连接您关心的事件,并通过用户控件本身的一些自定义事件属性发布它们。 一个简单的例子是包装一个按钮点击事件:
// CustomControl.cs
// Assumes a Button 'myButton' has been added through the designer
// we need a delegate definition to type our event
public delegate void ButtonClickHandler(object sender, EventArgs e);
// declare the public event that other classes can subscribe to
public event ButtonClickHandler ButtonClickEvent;
// wire up the internal button click event to trigger our custom event
this.myButton.Click += new System.EventHandler(this.myButton_Click);
public void myButton_Click(object sender, EventArgs e)
{
if (ButtonClickEvent != null)
{
ButtonClickEvent(sender, e);
}
}
然后,在使用该控件的 Form 中,您可以像其他任何事件一样连接该事件:
// CustomForm.cs
// Assumes a CustomControl 'myCustomControl' has been added through the desinger
this.myCustomControl.ButtonClickEvent += new System.EventHandler(this.myCustomControl_ButtonClickEvent);
myCustomControl_ButtonClickEvent(object sender, EventArgs e)
{
// do something with the newly bubbled event
}
如果有人仍然想知道如何在 WinForm 中模拟事件冒泡,那么Application.AddMessageFilter方法是一个很好的地方。
使用此方法,您可以安装自己的过滤器,该过滤器会监视发布到当前线程的消息队列的所有消息。
您应该知道此过滤器无法处理正在发送(未发布)的消息。 Fourtounatly,最有趣的事件(如点击事件)被发布而不发送,因此可以被这个过滤器监控
我想补充一点,正如所描述的,这实际上听起来像是在追逐红鲱鱼。 虽然看起来 WinForms 中缺少事件冒泡会给您带来麻烦,但实际情况是,糟糕的架构迫使您在不应该使用事件冒泡时需要使用事件冒泡。
如果您可以重构/重构您的设计,以便控件使用通用数据模型(MVC/MVP 是显而易见的选择),那么您可以简单地在模型上应用常见的 WinForms 模式(如 PropertyChanged 事件)来告诉您的主窗体和任何其他控件消耗这些数据来更新自己。
简而言之,其他答案是合理的,因为它们按要求回答了问题。 但从代码质量的角度来看,我认为更好的答案是将数据与 UI 分开。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.