自定义服务器控件中动态添加的 PostBackTrigger 未正确呈现
我正在构建一个派生自 CompositeControl
的自定义服务器控件。
该控件包含许多子控件(Labels、DropDownList、ListSearchExtender 等)。它们全部驻留在 UpdatePanel
内。
该控件还发布事件。为此,我添加了两个属性:EnableCallBacks 和 CallBacksAsPostBacks。这两个属性应该配置更新面板的回发行为。
有什么想法正确的实现应该是什么样子吗?
我的实现方式遇到了一些问题:
PostBackTrigger 并不总是渲染到输出 html 中。
在
CreateChildControls
方法中同时使用Triggers.Add(trigger)
和Controls.Add(_updatePanel)
会导致 PostBackTrigger 始终被渲染,即使我稍后将其删除(例如在 RenderControl() 或 PreRender() 内)。如果我不在这里添加触发器而是稍后添加,那么它永远不会被渲染。在此阶段,我还没有所有属性的正确值(例如EnableCallBacks
和CallBacksAsPostBacks
)。不可能将
Controls.Add(_updatePanel)
语句放在 RenderControl 方法内,因为它对于 AJAX 来说太晚了(最新的是PreRender() 否则我会得到一个异常)。
理想情况下,我会在 CreateChildControls() 中实例化所有控件,然后稍后在 PreRender 或 RenderControl 中设置它们的值
在
PreRender
方法中使用这两个语句会导致触发器根据包含页面中的设置正确呈现,但我没有从 DropDownList 中填充其数据ViewState(在调用/回发时)。
protected override void CreateChildControls()
{
base.CreateChildControls();
_updatePanel = new UpdatePanel();
_updatePanel.ID = "FprDropDownList_UpPnl";
_updatePanel.UpdateMode = UpdatePanelUpdateMode.Conditional;
_label = new FprLabel();
_label.ID = "FprDropDownList_Lbl";
_updatePanel.ContentTemplateContainer.Controls.Add(_label);
_dropDownList = new DropDownList();
_dropDownList.ID = "FprDropDownList_Ddl";
_dropDownList.CssClass = "fprDropDownList";
_dropDownList.AutoPostBack = true;
_updatePanel.ContentTemplateContainer.Controls.Add(_dropDownList);
_label.AssociatedControlID = _dropDownList.ClientID;
_listSearchExtender = new ListSearchExtender();
_listSearchExtender.ID = "FprDropDownList_Lse";
_listSearchExtender.TargetControlID = _dropDownList.ClientID;
_listSearchExtender.PromptPosition = ListSearchPromtPosition;
_listSearchExtender.PromptCssClass = "fprListSearchExtender";
_updatePanel.ContentTemplateContainer.Controls.Add(_listSearchExtender);
_ddlPostBackTrigger = new PostBackTrigger();
_ddlPostBackTrigger.ControlID = _dropDownList.ClientID;
//_updatePanel.Triggers.Add(_ddlPostBackTrigger);
Controls.Add(_updatePanel);
}
protected override void OnPreRender(EventArgs pE)
{
if (EnableCallBacks)
{
_dropDownList.SelectedIndexChanged += DropDownList_SelectedIndexChanged;
}
if (EnableCallBacks && CallBacksAsPostBacks)
{
_updatePanel.Triggers.Add(_ddlPostBackTrigger);
}
//Controls.Add(_updatePanel);
base.OnPreRender(pE);
}
public override void RenderControl(HtmlTextWriter pWriter)
{
// Do some things... like set Enable-state of child controls
base.RenderControl(pWriter);
}
I'm building a custom server control derived from CompositeControl
.
The control contains a number of child controls (Labels, DropDownList, ListSearchExtender, etc). All of them reside inside an UpdatePanel
.
The control also publishes events. For this I added two Properties: EnableCallBacks and CallBacksAsPostBacks. Those two properties should configure the postback behaviour of the update panel.
Any ideas what a correct implementation should look like?
I'm getting some problems with the way I implemented it:
the PostBackTrigger does not always get rendered into the output html.
Having both
Triggers.Add(trigger)
andControls.Add(_updatePanel)
inside theCreateChildControls
methods leads to the PostBackTrigger always being rendered, even if I remove it later on (e.g. within RenderControl() or PreRender()). If I do not add the trigger here but later on, then it does never get rendered. At this stage I do not have the correct values of all my properties yet (e.g.EnableCallBacks
andCallBacksAsPostBacks
).It is not possible to place the statement of
Controls.Add(_updatePanel)
inside the RenderControl-method due to it beeing too late for AJAX (latest istPreRender()
otherwise I get an exception).Ideally I would instantiate all controls in CreateChildControls() and then set their values later on in e.g. PreRender or RenderControl
Having both statements in the
PreRender
method results in, that the trigger gets rendered corretly depending on my settings in the containing page, but I don't get the DropDownList populated with its data from the ViewState (on call/postbacks).
protected override void CreateChildControls()
{
base.CreateChildControls();
_updatePanel = new UpdatePanel();
_updatePanel.ID = "FprDropDownList_UpPnl";
_updatePanel.UpdateMode = UpdatePanelUpdateMode.Conditional;
_label = new FprLabel();
_label.ID = "FprDropDownList_Lbl";
_updatePanel.ContentTemplateContainer.Controls.Add(_label);
_dropDownList = new DropDownList();
_dropDownList.ID = "FprDropDownList_Ddl";
_dropDownList.CssClass = "fprDropDownList";
_dropDownList.AutoPostBack = true;
_updatePanel.ContentTemplateContainer.Controls.Add(_dropDownList);
_label.AssociatedControlID = _dropDownList.ClientID;
_listSearchExtender = new ListSearchExtender();
_listSearchExtender.ID = "FprDropDownList_Lse";
_listSearchExtender.TargetControlID = _dropDownList.ClientID;
_listSearchExtender.PromptPosition = ListSearchPromtPosition;
_listSearchExtender.PromptCssClass = "fprListSearchExtender";
_updatePanel.ContentTemplateContainer.Controls.Add(_listSearchExtender);
_ddlPostBackTrigger = new PostBackTrigger();
_ddlPostBackTrigger.ControlID = _dropDownList.ClientID;
//_updatePanel.Triggers.Add(_ddlPostBackTrigger);
Controls.Add(_updatePanel);
}
protected override void OnPreRender(EventArgs pE)
{
if (EnableCallBacks)
{
_dropDownList.SelectedIndexChanged += DropDownList_SelectedIndexChanged;
}
if (EnableCallBacks && CallBacksAsPostBacks)
{
_updatePanel.Triggers.Add(_ddlPostBackTrigger);
}
//Controls.Add(_updatePanel);
base.OnPreRender(pE);
}
public override void RenderControl(HtmlTextWriter pWriter)
{
// Do some things... like set Enable-state of child controls
base.RenderControl(pWriter);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您应该在 PreInit 中添加动态控件,以便事件正确触发。
You should add your dynamic controls in PreInit for the events to fire properly.