我和另一位调查此事的同事花了两天时间。我很惊讶,因为大多数解决这个问题的解决方案都有错误的解决方案或解决方案,我认为这是错误的原因。
我们有一个自定义按钮控件,需要在按下时引发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
处理程序,因此没有任何反应。没有事件处理程序被调用。
备注:
IPostBackDataHandler
并从RaisePostBackEvent()
调用IPostBackDataHandler::RaisePostDataChangedEvent()
会导致在表单标记内部的接受按钮上正确引发事件。RegisterRequiresRaiseEvent(btnAccept)
将事件正确路由到接受按钮。问题:
上述工作方法的正确解决方案是什么?还是有其他解决方案吗?我们需要它才能使页面上的多个按钮可以引发独立的点击事件,而不考虑它们在页面上的顺序或位置。
我的想法:
__doPostback()
调用__EVENTTARGET
会自动将事件正确地路由到按钮,但实际上并没有发生这种情况。只有在我们实施IPostBackDataHandler
时才会发生这种情况。网络上的许多解决方案似乎都指向__doPostback
,UniqueID等作为实际实施IPostBackDataHandler
的罪魁祸首,这似乎解决了这个问题。IPostBackEventHandler
但不实施IPostBackDataHandler
。我认为这是正确的,因为控件不需要引发任何数据驱动的事件。因此,实施IPostBackDataHandler
以使其正常运行似乎是一种黑客攻击。RegisterRequiresRaiseEvent
是不直观的,如果页面上的多个按钮想要引发事件,则无法使用。asp:Button
是如何做到的?答案 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
在关闭按钮上。
对不起,如果我没有解决问题。