DataSource parameter for code-behind property
Here's some code for a server control "PropertyParameter" that you can use as a SelectParameter in your xyzDataSource that binds (one-way!) to a property value that is defined in code behind. This is something I need sometimes and isn't available out-of-the-box.
This method uses reflection and requires the property in code-behind to be public. There are two implementations, one for a Page and one for a UserControl. You will need to specify the Target property if you use it inside a UserControl.
This is how you use it in your markup:
<asp:ObjectDataSource ID="StatusObjectDataSource" runat="server"
TypeName="Components.WorkflowSecurity.WorkflowComponent"
SelectMethod="GetAvailableStatusesForEntityType">
<SelectParameters>
<controls:PropertyParameter Name="entityType"
PropertyName="EntityType" Target="Page" />
</SelectParameters>
</asp:ObjectDataSource>
Here is the the code for the server control:
public class PropertyParameter : Parameter
{
public enum PropertyTargetEnum
{
Page,
UserControl
}
public string PropertyName { get; set; }
public PropertyTargetEnum Target { get; set; }
public PropertyParameter()
{
Target = PropertyTargetEnum.Page;
}
protected override object Evaluate(
HttpContext context, Control control)
{
if (string.IsNullOrEmpty(PropertyName))
{
throw new ArgumentNullException("PropertyName");
}
Control targetControl = ResolvePropertyTarget(control);
Type pageType = targetControl.GetType();
PropertyInfo pi = pageType.GetProperty(PropertyName,
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic);
if (pi == null)
{
throw new InvalidOperationException(
string.Format("Property '{0}' not found on {1}.",
PropertyName, Target));
}
return pi.GetValue(targetControl, null);
}
private Control ResolvePropertyTarget(Control control)
{
switch (Target)
{
case PropertyTargetEnum.Page:
return control.Page;
case PropertyTargetEnum.UserControl:
return FindParentUserControl(control);
}
throw new ArgumentException("Invalid target type.");
}
private UserControl FindParentUserControl(Control control)
{
Control parent = control.Parent;
while (parent != null)
{
if (parent is UserControl)
{
return (UserControl)parent;
}
parent = parent.Parent;
}
throw new ArgumentException(string.Format(
"'{0}' is not inside a UserControl.",
control.ID));
}
}
Btw, there are two common workarounds if you don't like this implementation:
- Store the value in a HiddenField and use a ControlParameter instead
- Add a Parameter control; implement the OnSelecting event of the DataSource to set the value on the InputParameters collection