调用错误控件的RaisePostBackEvent

时间:2015-07-21 13:10:38

标签: asp.net user-controls custom-controls

我和另一位调查此事的同事花了两天时间。我很惊讶,因为大多数解决这个问题的解决方案都有错误的解决方案或解决方案,我认为这是错误的原因。

我们有一个自定义按钮控件,需要在按下时引发ServerClick事件。以下是汇总代码:

public class MyButton : WebControl, IPostBackEventHandler
{
    protected HtmlGenericControl _Button;
    protected string _OnClick = "";
    protected string _Name;
    public event EventHandler ServerClick;
    // etc...    

    public MyButton()
    {
        Width = Unit.Pixel(100);
        _Button = new HtmlGenericControl("button");
        Controls.Add(_Button);
    }

    protected override void Render(HtmlTextWriter writer)
    {
        _Button.Attributes.Add("id", string.IsNullOrEmpty(_Name) ? base.ID : _Name);
        _Button.Attributes.Add("name", _Name);

        // etc...

        _OnClick = Page.ClientScript.GetPostBackEventReference(this, "");
        _Button.Attributes.Add("onClick", _OnClick);

        // etc...

        ID = String.Empty;
        Name = String.Empty;
        AccessKey = String.Empty;
        TabIndex = -1;
        Width = Unit.Empty;

        base.Render(writer);
    }

    protected virtual void OnServerClick()
    {
        if (this.ServerClick != null)
        {
            this.ServerClick(this, new EventArgs());
        }
    }

    public void RaisePostBackEvent(string eventArgument)
    {
        this.OnServerClick();
    }
}

在浏览器端,代码使用其中两个按钮

<form>

    <!-- etc ... -->

    <div class="row actionBar">
        <PGSC:MyButton Name="btnAccept" ID="btnAccept" LabelID="3244" TabIndex="70" runat="server" OnServerClick="AcceptClickHandler"/>
        <PGSC:MyButton Name="btnClose" ID="btnClose" LabelID="349" OnClick="window.returnValue=frmMMD.hdnMmdId.value;window.close();" TabIndex="80" runat="server" />
    </div>
</form>

问题: 接受按钮不会引发该事件。调试显示RaisePostBackEvent被调用,但在关闭按钮上,没有附加ServerClick处理程序,因此没有任何反应。没有事件处理程序被调用。

备注:

  • 如果页面上只有一个MyButton,则看不到问题。
  • 如果按钮被重新排序,使得接受按钮是页面上的最后一个按钮,则它开始工作。
  • 移动窗体标记之外的按钮会导致事件按预期工作,并且正确调用接受按钮事件处理程序。
  • 实施IPostBackDataHandler并从RaisePostBackEvent()调用IPostBackDataHandler::RaisePostDataChangedEvent()会导致在表单标记内部的接受按钮上正确引发事件。
  • 在PageLoad期间调用RegisterRequiresRaiseEvent(btnAccept)将事件正确路由到接受按钮。

问题:

上述工作方法的正确解决方案是什么?还是有其他解决方案吗?我们需要它才能使页面上的多个按钮可以引发独立的点击事件,而不考虑它们在页面上的顺序或位置。

我的想法:

  • 这个问题似乎在这里讨论:http://forums.asp.net/t/1074998.aspx?ASP+NET+RaisePostbackEvent+Issues
  • 一方认为使用正确的__doPostback()调用__EVENTTARGET会自动将事件正确地路由到按钮,但实际上并没有发生这种情况。只有在我们实施IPostBackDataHandler时才会发生这种情况。网络上的许多解决方案似乎都指向__doPostback,UniqueID等作为实际实施IPostBackDataHandler的罪魁祸首,这似乎解决了这个问题。
  • 控制实施IPostBackEventHandler但不实施IPostBackDataHandler。我认为这是正确的,因为控件不需要引发任何数据驱动的事件。因此,实施IPostBackDataHandler以使其正常运行似乎是一种黑客攻击。
  • 使用RegisterRequiresRaiseEvent是不直观的,如果页面上的多个按钮想要引发事件,则无法使用。
  • 我想知道,asp:Button是如何做到的?

1 个答案:

答案 0 :(得分:0)

我模拟了一个情况。 希望能帮助到你。 有MyButton WebServerControl类:

[DefaultProperty("Text")]
[ToolboxData("<{0}:MyButton runat=server></{0}:MyButton>")]
public class MyButton : WebControl, IPostBackEventHandler
{
    [Bindable(true)]
    [Category("Appearance")]
    [DefaultValue("")]
    [Localizable(true)]
    public string Text
    {
        get
        {
            String s = (String)ViewState["Text"];
            return ((s == null) ? String.Empty : s);
        }

        set
        {
            ViewState["Text"] = value;
        }
    }

    protected HtmlGenericControl _Button;
    protected string _OnClick = "";
    protected string _Name;
    public event EventHandler ServerClick;
    // etc...    

    public MyButton()
    {
        Width = Unit.Pixel(100);
        _Button = new HtmlGenericControl("button");
        Controls.Add(_Button);
    }

    protected override void Render(HtmlTextWriter writer)
    {
        _Button.Attributes.Add("id", string.IsNullOrEmpty(_Name) ? base.ID : _Name);
        _Button.Attributes.Add("name", _Name);

        // etc...

        _OnClick = Page.ClientScript.GetPostBackEventReference(this, "");
        _Button.Attributes.Add("onClick", _OnClick);

        // etc...

        ID = String.Empty;
        //Name = String.Empty;
        AccessKey = String.Empty;
        TabIndex = -1;
        Width = Unit.Empty;

        base.Render(writer);
    }

    protected virtual void OnServerClick()
    {
        if (this.ServerClick != null)
        {
            this.ServerClick(this, new EventArgs());
        }
    }

    public void RaisePostBackEvent(string eventArgument)
    {
        this.OnServerClick();
    }
}

然后我在项目中使用了我的Web服务器控件,让我们说这是default.aspx:

<div><cc1:MyButton ID="btnAccept" runat="server" TabIndex="70"   OnServerClick="AcceptClickHandler" />
<cc1:MyButton ID="btnClose" Text="Close" Width="256px" LabelID="349" runat="server" TabIndex="80" /></div><div>
    <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</div>

在default.aspx.cs中,我实现了简单的事件:

protected void AcceptClickHandler(object sender, EventArgs e)
    {
        Label1.Text = DateTime.Now.ToLongTimeString();
    }

只有在单击“接受”按钮时才会触发AcceptClickHandler 在关闭按钮上。
对不起,如果我没有解决问题。