如何在用户控件中创建事件并在主窗体中处理它?

86

我有一个自定义的用户控件,想要实现相对简单的功能。

每当该用户控件中的数字微调框的值发生变化时,让主窗体更新显示窗口。

如果数字微调框不在用户控件中,这并不是问题,但是我似乎无法弄清如何让事件由主窗体处理而不是用户控件处理。


1
可能是Winforms用户控件自定义事件的重复问题。 - John Saunders
5个回答

157
你需要为用户控件创建一个事件处理程序,当用户控件内部触发事件时,可以将该事件冒泡到链中,以便你可以从表单处理事件。
在用户控件上单击Button1后,会触发Button1_Click,从而在表单上触发UserControl_ButtonClick事件。
用户控件:
[Browsable(true)] [Category("Action")] 
[Description("Invoked when user clicks button")]
public event EventHandler ButtonClick;

protected void Button1_Click(object sender, EventArgs e)
{
    //bubble the event up to the parent
    if (this.ButtonClick!= null)
        this.ButtonClick(this, e);               
}

表单:

UserControl1.ButtonClick += new EventHandler(UserControl_ButtonClick);

protected void UserControl_ButtonClick(object sender, EventArgs e)
{
    //handle the event 
}

注:

  • 较新的Visual Studio版本建议使用ButtonClick?.Invoke(this, e);代替if (this.ButtonClick!= null) this.ButtonClick(this, e);,两者实际上是一样的,只是前者更短。

  • Browsable属性可以使事件在Visual Studio设计器(事件视图)中可见,Category将其显示在“操作”类别中,而Description为其提供了描述。您可以完全省略这些属性,但是让它在设计器中可用会更加方便,因为VS会代表您处理它们。


我在使用生成用户控件实例的重复器控件上遇到了问题,它们是在OnItemDatabound事件中生成的。好像UserControl1.ButtonClick += new EventHandler(UserControl_ButtonClick);这一部分没有起作用。if (this.ButtonClick!= null)总是返回false。 - Osprey
1
@Osprey:在一个重复器内部,您可能希望在标记中声明性地添加处理程序,例如 <asp:Button runat="server" OnClick="btnTest_Click" />。否则,在重复器的数据绑定期间,您需要找到用户控件并在那里附加事件处理程序。 - James Johnson

28

尝试映射它。 将此代码放置在您的UserControl中:

public event EventHandler ValueChanged {
  add { numericUpDown1.ValueChanged += value; }
  remove { numericUpDown1.ValueChanged -= value; }
}

然后你的UserControl将具有NumericUpDown控件通常显示的ValueChanged事件。


2
不要在这里使用 new 关键字。 - Hans Passant

14

您可以这样做......以下示例显示文本框(用户控件)的值已更改

   // Declare a delegate 
public delegate void ValueChangedEventHandler(object sender, ValueChangedEventArgs e);
public partial class SampleUserControl : TextBox 
{    
    public SampleUserControl() 
    { 
        InitializeComponent(); 
    }

    // Declare an event 
    public event ValueChangedEventHandler ValueChanged;

    protected virtual void OnValueChanged(ValueChangedEventArgs e) 
    { 
        if (ValueChanged != null) 
            ValueChanged(this,e); 
    }    
    private void SampleUserControl_TextChanged(object sender, EventArgs e) 
    { 
        TextBox tb  = (TextBox)sender; 
        int value; 
        if (!int.TryParse(tb.Text, out value)) 
            value = 0; 
        // Raise the event 
       OnValueChanged( new ValueChangedEventArgs(value)); 
    }    
}

0

其中一种简单的方法是使用Lambda函数,没有任何问题。

userControl_Material1.simpleButton4.Click += (s, ee) =>
            {
                Save_mat(mat_global);
            };

-1

对于那些想在VB中实现此操作的人,这是我如何使用复选框使其工作的方法。

背景:我正在尝试制作自己的复选框,它是一个滑块/开关控件。我仅包括了与此问题相关的代码。

在用户控件MyCheckbox.ascx中

<asp:CheckBox ID="checkbox" runat="server" AutoPostBack="true" />

在用户控件MyCheckbox.ascx.vb中

创建一个事件处理程序(OnCheckChanged)。当您的用户控件(MyCheckBox.ascx)内部的控件(ID="checkbox")触发事件时,触发您的事件处理程序(OnCheckChanged)。

Public Event OnCheckChanged As EventHandler

Private Sub checkbox_CheckedChanged(sender As Object, e As EventArgs) Handles checkbox.CheckedChanged
    RaiseEvent OnCheckChanged(Me, e)
End Sub

在页面 MyPage.aspx 中

<uc:MyCheckbox runat="server" ID="myCheck" OnCheckChanged="myCheck_CheckChanged" />

注意:直到我添加下面的Handles子句,myCheck_CheckChanged才会触发。

在页面MyPage.aspx.vb中

Protected Sub myCheck_CheckChanged (sender As Object, e As EventArgs) Handles scTransparentVoting.OnCheckChanged
    'Do some page logic here
End Sub

我知道你在2年前回答了这个问题,但是那个问题是关于WinForms的,而不是ASP.Net——虽然一般的想法是相似的(使用事件处理程序),但在WinForms中的实现会有所不同。 - Justin Greywolf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接