Problems with DataSource controls
I have blogged about Problems with ObjectDataSource control some time ago. That was a problem I was aware of for some time now. It was until recently when I have come across yet another problem. This time it is with how the DataSource controls handle the SelectParameters. I'm mainly working with business objects so I have little experience using the SqlDataSource but from what I have seen it uses the same mechanism for specifying parameters. The problem is that you can only select a fixed number of parameter sources:
It often happens that you need to get a value from some other location such as a property on a page. What to do when such a need arises? Worry not! There is a solution. You will have to create your own class derived from the Parameter class from System.Web.UI.WebControls namespace. You will need to overwrite some of the methods. As an example I present the TemplateContainerParameter which makes it possible to use public properties defined on a page or a user control as a parameter providers.
public class TemplateControlParameter : Parameter
{
protected override object Evaluate(
HttpContext context, Control control)
{
if ((control == null) || (string.Empty.Equals(PropertyName)))
{ return null; }
TemplateControl templateControl = control.TemplateControl;
Type type = templateControl.GetType();
PropertyInfo property = type.GetProperty(PropertyName);
if (property == null)
{ return null; }
return property.GetValue(templateControl, null);
}
protected override Parameter Clone()
{
TemplateControlParameter parameter =
new TemplateControlParameter();
parameter.PropertyName = this.PropertyName;
return parameter;
}
public string PropertyName
{
get { return (string)ViewState["PropertyName"] ?? string.Empty; }
set
{
if (PropertyName != value)
{
ViewState["PropertyName"] = value;
base.OnParameterChanged();
}
}
}
}
The interesting part here is using the TemplateControl property which will return the reference to a nearest template control containing our parameter which in most cases will be either page or a user control. You can also create a parameter which always uses page properties:
protected override object Evaluate(
HttpContext context, Control control)
{
if ((context == null) || (string.Empty.Equals(PropertyName)))
{ return null; }
IHttpHandler handler = context.Handler;
Type type = handler.GetType();
PropertyInfo property = type.GetProperty(PropertyName);
if (property == null)
{ return null; }
return property.GetValue(handler, null);
}
Here the interesting part is using the Handler property of the context object which in most cases will return the reference to a page object but hidden behind the IHttpHandler interface. It does not mather though since we are getting the property value using Reflection.
The bad news is that you will not be able to use those custom parameters in the designer :-(. The 6 parameter sources shown on the picture above are hard-coded in the .NET Framework library (to my best knowledge). You have to resort to the html editor - as in many more cases, more than it should be necessary :-(.