调用错误控件的RaisePostBackEvent

Ali*_*Ali 9 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

<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>
Run Code Online (Sandbox Code Playgroud)

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

笔记:

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

问题:

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

我的想法:

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

小智 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我在一个项目中使用了我的 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>
Run Code Online (Sandbox Code Playgroud)

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

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

AcceptClickHandler 仅在单击“接受”按钮时触发,而不是在单击“关闭”按钮时触发。
抱歉,如果我没有解决问题。