11

主窗体有什么方法能够拦截在用户控件上的子控件上触发的事件?

我在我的应用程序的主窗体中嵌入了一个自定义用户控件。该控件包含各种操作数据的子控件,这些子控件本身由主窗体上的其他控件显示。我想要的是,如果用户更改子控件时可以以某种方式通知主窗体,那么我可以在其他地方更新数据和相应的显示。

现在,我在作弊。我有一个委托连接到子控件的焦点离开事件。这个委托改变了我没有在其他地方使用的用户控件的一个属性(在这个原因中,CausesValidation)。然后,我在主窗体上定义了一个委托,用于当用户控件的 CausesValidation 属性发生更改时,它会指示应用程序更新数据并显示。

出现问题是因为我还为焦点离开用户控件时设置了一个委托,因为我需要先验证用户控件中的字段,然后才能允许用户执行其他任何操作。但是,如果用户只是在子控件之间切换,我不想验证,因为它们可能没有完成编辑。

基本上,我希望在用户切换子控件或离开用户控件时更新数据,但不进行验证。当用户离开控件时,我想更新并验证。现在,离开用户控件会导致验证触发两次。

4

5 回答 5

15

最佳实践是在将事件UserControl冒泡到父表单的事件上公开事件。我已经开始为你整理了一个例子。以下是此示例提供的内容的描述。

  • UserControl1
  • 创建UserControl一个TextBox1
  • UserControl在被叫上注册一个公共事件ControlChanged
  • 在寄存器中为TextChangedEventUserControl的事件处理程序TextBox1
  • TextChangeEvent处理程序函数中,我调用ControlChanged事件以冒泡到父表单
  • Form1
  • UserControl1在设计器上放置一个实例
  • UserControl1在forMouseLeave和 for上注册一个事件处理程序ControlChanged

这是一个屏幕截图,说明ControlChanged我在 上定义的事件UserControl可通过父 Windows 窗体上的 Visual Studio 中的 UX 获得。

用于用户控制的事件处理程序

于 2008-10-02T16:14:45.080 回答
2

此类事情的最佳模型是在您的用户控件上创建自定义事件,并在适当的时间引发它们。

您的场景相当复杂,但并非闻所未闻。(实际上,在我当前的一个项目中,我处于非常相似的模式。)我处理它的方式是用户控件负责自己的验证。我不使用 CausesValidation;相反,在适当的用户控制点,我通过覆盖 ValidateChildren() 来执行验证。(对我来说,这通常发生在用户单击用户控件上的“保存”或“下一步”时。)

不熟悉您的用户控件 UI,这可能不是 100% 适合您的方法。但是,如果您引发自定义事件(可能使用指定是否执行验证的自定义 EventArgs),您应该能够到达您想要的位置。

于 2008-10-02T15:53:09.500 回答
2

您将需要连接您关心在用户控件中捕获的事件,并通过用户控件本身的一些自定义事件属性发布它们。一个简单的例子是包装一个按钮点击事件:

// 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);
  }
}

然后,在使用该控件的表单中,您可以像其他任何方式一样连接事件:

// 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
}
于 2010-03-29T18:25:23.323 回答
1

如果有人仍然想知道如何在 WinForm 中模拟事件冒泡,那么Application.AddMessageFilter方法是一个不错的选择。

使用这种方法,您可以安装自己的过滤器来监控所有发布到当前线程的消息队列的消息。

您应该知道此过滤器无法处理正在发送(未发布)的消息。Fourtounatly,最有趣的事件(如点击事件)被发布而不被发送,因此可以被这个过滤器监控

于 2015-02-04T20:03:52.053 回答
0

如前所述,我想插话,听起来你实际上是在追逐一条红鲱鱼。虽然您似乎遇到了 WinForms 中缺少事件冒泡导致您遇到麻烦的情况,但现实情况是,糟糕的架构迫使您在不应该需要事件冒泡的情况下需要事件冒泡。

如果您可以重构/重构您的设计,以便控件使用通用数据模型(MVC/MVP 是显而易见的选择),那么您可以简单地在模型上应用常见的 WinForms 模式(如 PropertyChanged 事件)来告诉您的主窗体和任何其他控件它消耗这些数据来更新自己。

简而言之,其他答案是合理的,因为它们按要求回答了问题。但从代码质量的角度来看,我认为更好的答案是将数据与 UI 分开。

于 2010-03-29T18:34:59.840 回答