Reliably adding Controls or Markup before or after an ASP.NET Control?
In my last post I was waxing on about the problems with <%= %> markup in pages and content containers and the inability to use Control.Controls.Add() to add controls dynamically at runtime. If you do this you get a nasty error message that 'The Control Collection cannot be modified because the control contains code blocks'.
To put this in context, what I'm trying to do is to dynamically generate binding error messages as controls are unbound from databinding, and then display them without requiring to put validators on the page first. The idea is you add a DataBinder to the page, and the DataBinder extends any control on the page. You set binding properties a few possible validation settings (IsRequired) and then call DataBind() to bind the form controls, UnBind()to bind the data from the control back into the binding source. Any errors that occur, are picked up and dumped into a BindingError Collection. The errors also trigger the insertion of binding error messages on the controls. At the moment Controls.Add() is used which has the reliability problem mentioned above.
It works great – as long as there are no script <%= %> markup tags on the page or content container. I mentioned yesterday some workarounds to make this work by using <%# %> Databinding expressions or wrapping the script code/tags into a separate server container tag like <div runat="server"> which effectively removes the script from the parsing container.
All that's all fine and good, but I want this to be a generic solution so these workarounds are not quite cutting it.
So, I started looking for some other solutions. I figured there would be some way to override the rendering of the control or rather hook the rendering and then inject markup afterwards. It looked like Control.SetRenderMethodDelegate() would work to hook the control's rendering, but as it turns out SetRenderMethodDelegate() is applied only to Container controls, and only fires for the control's inner content. It doesn't fire on typical controls like TextBox and even if it did it wouldn't do me any good to override the content rendering. I want to hook the 'outer' rendering so I can inject markup before or after the Control's Render() method fires.
So, there's no way to hook the rendering of a control, from outside of the control itself. This seems to be a pretty big omission in ASP.NET. The combination of the <% %> markup behavior of Control.Controls.Add() and the lack of some hook that allows hooking into the Rendering of a control externally seems really limiting. It makes it difficult to reliably build extender controls that might need to expand on the functionality of existing controls, which is exactly what I'm doing here.
So, question: Does anybody see a way to do what I'm trying to do, reliably beyond the hacky workarounds I've described here? Anybody know of a way to create pre or post markup for a control externally (ie. without overriding the control class itself)?
Other Posts you might also like
- Adding minimal OWIN Identity Authentication to an Existing ASP.NET MVC Application
- Resolving Paths To Server Relative Paths in .NET Code
- Map Physical Paths with an HttpContext.MapPath() Extension Method in ASP.NET
- Back to Basics: Rewriting a URL in ASP.NET Core
- Getting the Client IP Address in ASP.NET Core
The Voices of Reason
# re: Reliably adding Controls or Markup before or after an ASP.NET Control?
I’m currently working on my own data binding solution that is similar to yours. I’m also trying to figure out a way to display broken rule messages and icons for controls without having to subclass the controls :-). I have come up with one possible work around. It does not provide the flexibility of adding additional server side controls, but uses Javascript. I have not gotten very far, but the basic Javascript can be found below (I don’t know Javascript very well, so I’m sure there is a better way to do what I’m doing and make it work on different browsers). The important point is that it works! So far :-). I can send you a working example if you would like.
Obvious if someone can come up with a way to add controls to the Control Collection that would be a better solution.
Hope this helps.
<script type="text/javascript" language="javascript">
function DisplayBrokenRules()
{
// PATH TO WARNING IMAGE
var WarningImgPath = "Images/warning.gif";
/* CLASS NAME FOR SPAN TAG THAT WILL ENCLOSE THE CONTROL.
* THIS ALLOWS FOR ADDITIONAL FORMATING I.E. BACKGROUND COLOR, BORDER, ETC. */
var ClassName = "Error";
// LIST OF CONTROL ID'S THAT SHOULD DISPLAY AN ERROR MESSAGE
var controlIdArry = new Array("tbFirstName","tbAge")
var errorMesages = new Array("Please Enter First Name",
"Age must be greater then 0");
// LOOP THROUGH ARRAY OF CONTROLS TO DISPLAY ERROR MESSAGES
var i;
for (i in controlIdArry)
{
// GET CONTROL
var control = document.getElementById(controlIdArry[i]);
// CREATE SPAN TAG
var span = document.createElement('span');
span.className = ClassName;
// CREATE IMAGE TAG TO DISPLAY ERROR ICON
var img = document.createElement('img');
img.src = WarningImgPath;
img.title = errorMesages[i]; // DISPLAY ERROR AS TOOP TIP
// APPEND THE CONTROL INSIDE THE SPAN ELEMENT
span.appendChild(control.cloneNode(false));
// APPEND IMAGE TAG INSIDE SPAN ELEMENT
span.appendChild(img.cloneNode(false));
// REPLACE THE CONTROL WITH THE SPAN ELEMENT
control.parentNode.replaceChild(span, control);
}
}
</script>
# re: Reliably adding Controls or Markup before or after an ASP.NET Control?
I'm hesitant to rely on client scripting.
As to the Control Collection - that works as long as there's no <% %> markup on the page or Content Panel. I posted the code I use in the previous message.
# re: Reliably adding Controls or Markup before or after an ASP.NET Control?
# re: Reliably adding Controls or Markup before or after an ASP.NET Control?
I don't know if you can map all the controls to one adapter with a .browser file like:
<adapter controlType="System.Web.UI.Control"
adapterType="MyAdapter" />
so if that works maybe it can help you.
If it doesn't work, another possibility could be to write a control adapter for the page itself and modify how it render its child controls.
# re: Reliably adding Controls or Markup before or after an ASP.NET Control?
Mucking around with web.config is not really my idea of 'user friendly' <g>. Then there's also the issue of additional adapters getting loaded that might thwart the whole thing.
Thanks for the thought thought - forced me to at least take a look at control adapters. <sigh> - so much information and things to keep track of. Who can keep up, even in our ASP.NET world alone...
# re: Reliably adding Controls or Markup before or after an ASP.NET Control?
Hopefully these scenarios get back to MS and the next version of the framework will gain ground.
I tend to avoid delicate balancing acts between elaborate client scripting and .NET.
# re: Reliably adding Controls or Markup before or after an ASP.NET Control?
Essentially a control adapter is a class that hooks up in all the events in the ASP.NET life cycle normally used to modify the rendering of a control.