DataBinding to a subcontrol...

F

Fred Hirschfeld

I am creating a new web control that will be a DropDownList that gets its
values dynamically from a Web Service based on user selections on the form
(client side). I have created the control and it has a collection of classes
that reference other webcontrols on the page. These referenced control are
the ones that drive the variable values passed as parameters to the web
service.

So for example I have DropDown1 control on the page that is a standard
DropDownList that is populated on the server using DataBind(). I have my new
control on the page and through the designer add the reference to DropDown1
to the property collection on DropDown2 (the new control that uses
services).

At design-time (initially) this all appears to be working but when I execute
the page, I get an error that the reference is NULL. I debug and see that
the objects are all created but the reference is not there in my custom
control. I have followed some descriptions I found that indicate the only
way to do this is to follow the DataBinding method use by DataSource (and
why my collection takes a Control derived class instead of a regular class).
Also, if I try to redesign the page, the bound control no longer has the
data binding.

I have tested the technique (and code I have) on a property on the base
control (rather than a collection) and it does maintain the designable
aspect and the code binds properly.

public class DropDownServicedList : WebControl {
...

private CustomCollection m_BoundParameters = new CustomCollection();

[
PersistenceMode(PersistenceMode.InnerProperty),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
NotifyParentProperty(true)
]
public CustomCollection BoundParameters {
get { return m_BoundParameters; }
}

...
}

public class CustomCollection : CollectionBase {
... standard implementation ...
}

// Derived from control for databinding...
[Designer("SierraSystems.Web.Controls.Design.BoundParameterControlDesigner,
SierraSystems.Web")]
public class BoundParameterControl : Control
{
private string m_ParameterName = string.Empty;
private WebControl m_BoundControl = null;

[NotifyParentProperty(true)]
public string ParameterName
{
get { return m_ParameterName; }
set { m_ParameterName = value; }
}

[
Browsable(true),
Bindable(true),
PersistenceMode(PersistenceMode.InnerProperty),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
NotifyParentProperty(true)
]
public WebControl BoundControl
{
get { return m_BoundControl; }
set { m_BoundControl = value; }
}

[
Browsable(false),
Bindable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public string BoundControlID
{
get
{
if (m_BoundControl != null)
return m_BoundControl.ClientID;

return string.Empty;
}
}

public BoundParameterControl()
{
}

public string GetControlValueJavascript()
{
return string.Format("{0}.options[{0}.selectedIndex].value",
m_ParameterName);
}
}

public class BoundParameterControlDesigner : ControlDesigner
{
public string BoundControl
{
get
{
DataBinding binding = DataBindings["BoundControl"];

if (binding != null)
{
return binding.Expression;
}

return string.Empty;
}
set
{
if ((value == null) || (value.Length == 0))
{
DataBindings.Remove("BoundControl");
}
else
{
DataBinding binding = DataBindings["BoundControl"];

if (binding == null)
{
binding = new DataBinding("BoundControl", typeof(WebControl), value);
}
else
{
binding.Expression = value;
}
DataBindings.Add(binding);
}

OnBindingsCollectionChanged("BoundControl");

IContainer container = (IContainer)this.GetService(typeof(IContainer));
((BoundParameterControl)this.Component).BoundControl =
container.Components[value] as WebControl;
}
}

protected override void PreFilterProperties(IDictionary properties)
{
base.PreFilterProperties(properties);

PropertyDescriptor prop = (PropertyDescriptor)properties["BoundControl"];

System.ComponentModel.AttributeCollection runtimeAttributes =
prop.Attributes;
Attribute[] attrs = new Attribute[runtimeAttributes.Count + 1];

runtimeAttributes.CopyTo(attrs, 0);
attrs[runtimeAttributes.Count] = new
TypeConverterAttribute(typeof(BoundParameterControlTypeConverter));
prop = TypeDescriptor.CreateProperty(this.GetType(), "BoundControl",
typeof(string), attrs);
properties["BoundControl"] = prop;
}
}



public override StandardValuesCollection
GetStandardValues(ITypeDescriptorContext context)
{
object[] components = null;

if (context != null)
{
ArrayList list = new ArrayList();
list.Add(null);

IContainer cont = context.Container;
if (cont != null)
{
ComponentCollection objs = cont.Components;
foreach(IComponent obj in objs)
{
if (obj is DropDownList || obj is DropDownServicedList)
{
list.Add(obj.Site.Name);
}
}
}

components = list.ToArray();
}

return new StandardValuesCollection(components);
}

public override bool GetStandardValuesExclusive(ITypeDescriptorContext
context)
{
return true;
}

public override bool GetStandardValuesSupported(ITypeDescriptorContext
context)
{
return true;
}
}


Any ideas? I can add mode code here if it will help but there is a lot of it
and so I don't want to add it to this initial post. Below is the snippet of
HTML that is produced...



<sierra:dropdownservicedlist id="ddlActivities" runat="server"
UseSelectItem="True" ValueMember="@ActivityId"
ServiceURL="~/Services/DataLists.asmx/GetActivitiesByGroup"
SelectItemText="-- Select an Activity --">
<ParameterControls>
<sierra:BoundParameterControl ID="boundParameterControl1"
ParameterName="test" BoundControl='<%# ddlGroup %>'>
</sierra:BoundParameterControl>
</ParameterControls>
</sierra:dropdownservicedlist>

<!---------------------- Custom
DropDownList ----------------------------------->
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top