Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Collection property Hell on an ASP.NET Server Control


:P
On this page:

 

I’ve been fighting an odd problem today with a custom control I’m building. The control is another extender control that has a number of child items that track other items on the form. The markup looks something like this:

 

<ww:LocalizationExtender id="Localizer" runat="server">   

 <LocalizationItems>

    <ww:LocalizationItem ControlId="lblMessage"

                          Property="Text"  runat="server"

                          EnableLocalization="true"

                          LocalizationType="GlobalString">

    </ww:LocalizationItem>

    <ww:LocalizationItem  ControlId="btnSubmit"

                         Property="Text"

                          EnableLocalization="true"

                          LocalizationType="GlobalString">

    </ww:LocalizationItem>

  </LocalizationItems>

</ww:LocalizationExtender>

 

The logic in the control works fine at runtime. But when the control renders I get this error display:

 

 

Haeh? The problem is that LocalizationItems is a collection and it doesn’t have a LocalizationExtender property and well nothing of the sort gets set on LocalizationItems or the child items. Something isn’t wired right but I can’t figure out what the heck it is. I compared with other controls that have this same setup and it all looks right, but it looks that the designer is very unhappy.

 

It seems like an attribute mismatch, but I can’t see it in the code.

 

[ToolboxData("<{0}:LocalizationExtender runat=server />")]

//[ProvideProperty("LocalizationItem", typeof(Control))]

[NonVisualControl, Designer(typeof(LocalizationExtenderDesigner))]

[ParseChildren(true, "LocalizationItems")]

[PersistChildren(false)]

//[DefaultProperty("LocalizationItems")]

//[DefaultEvent("ValidateControl")]

public class LocalizationExtender : Control  //, IExtenderProvider

{

    private new bool DesignMode = HttpContext.Current == null;

               

    /// <summary>

    /// A collection of the individual Localization Items for the control

    /// that track each of the controls on the page that are localized.

    /// </summary>

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]

    [PersistenceMode(PersistenceMode.InnerProperty)]

    [Browsable(true)]

    public LocalizationItemCollection LocalizationItems

    {

        get { return _Items; }

        set { _Items = value; }

    }

    private LocalizationItemCollection _Items = new LocalizationItemCollection();

 

The collection just inherits from CollectionBase. I get the same error if I replace the manual collection with a List<LocalizationItem> - in fact I created the manual collection because of this damn error since this is the only difference I see between this control and another.

 

If take the child items out of the page, the control renders fine. If leave just the collection in place it too renders fine. But as soon as a child item is added into the collection in the designer it fails. The designer will let me add items visually and persist them fine. However, once I switch into markup and then back to the designer the control is hosed again.

 

I’ve tried to debug into this and see if I can capture the code failing somewhere, but even attached to the debugger into a second instance in VS I can’t find the spot that’s a problem. The main control OnInit() fires fine, but beyond that I get nothing. No collection or item constructors (presumably because they’re deserializing somehow) – nothing to hook code to and the debugger is not throwing exception dialogs either…

 

I’m stumped and I’m out of ideas on how to track this down… Anybody have any ideas? I need a little push <g>…


The Voices of Reason


 

Rick Strahl
August 18, 2006

# re: Collection property Hell on an ASP.NET Server Control

Aaaaaaaaaargh - Talking to yourself is really the best therapy. 10 minutes after posting I found the culprit...

It turns out the Property Setter of the Collection property was the problem:

set { _Items = value; }

Removing the Setter makes everything work just peachy. I'm not sure why the absence or existance of a Setter should make a difference to ASP.NET. In fact it seems like a setter would be required in order for ASP.NET...

At the very least it'd be nice if there was a sensible error message that kind of hinted at the problem...

<sigh> there go another couple of hours of a wild goosechase. Hopefully this will help somebody else out.

William
August 18, 2006

# re: Collection property Hell on an ASP.NET Server Control

Almost posted the same solution, but you got there before me :P

I spent almost an entire day on this a while ago, it makes not logical sense to me why the setting property would make a difference... but hey, mine is not to question why :p

Bertrand Le Roy
August 18, 2006

# re: Collection property Hell on an ASP.NET Server Control

If you have a setter, the parser will attempt to set the property directly using it, which will fail for various reasons. The pattern for collection properties is to make them get-only, so that the getter can lazily create the collection and can handle its state management. If you enable the setting of the collection, there is no way you can reliably and efficiently manage its state.

Rick Strahl
August 18, 2006

# re: Collection property Hell on an ASP.NET Server Control

Yup that makes sense. I realize it's not needed either of course, it's just one of those things that is real easy to overlook - especially since I use an Intellisense Macro to create properties with getters and setters simultaneously <s>...

A better error message might help though <g>...


Simone Busoli
August 18, 2006

# re: Collection property Hell on an ASP.NET Server Control

Hi Rick, thanks for your discoveries! I've never worked with collection properties, and since you've been experimenting with them I wanted to ask you if you get designer support for them.

Rick Strahl
August 18, 2006

# re: Collection property Hell on an ASP.NET Server Control

Yes, collections and generic collections get designer support with a stock collection editor. It works great...

Simone Busoli
August 18, 2006

# re: Collection property Hell on an ASP.NET Server Control


Simone Busoli
August 18, 2006

# re: Collection property Hell on an ASP.NET Server Control

Just to point out something that someone may find useful, if you declare a property collection to be an interface (like IList or its generic form) you won't receive designer support.
It took me a while to figure out why the designer didn't let me edit that property, but simply switching to List (or List<>) did the trick.

Rick Strahl
August 18, 2006

# re: Collection property Hell on an ASP.NET Server Control

Yes it needs to be a concrete type so that ASP.NET can figure out what the embedded type is.

If you don't get one by default you can create CollectionEditor and assign it. It's really simple to implement - all you need to do is provide the target type of the children and ASP.NET will do the rest.

But using List<> is usually the easiest unless you need mroe control (as I do for this control).


Simone Busoli
August 18, 2006

# re: Collection property Hell on an ASP.NET Server Control

Yes I read about the Editor which is useless if you use a strongly typed collection.
One more thing which is not told in the docs is that the inner type of the property collection must reside in the same namespace of the control or you'll need to register that other namespace with the <%@ Register %> directive because it doesn't get recognized and considered as an HtmlGenericControl.

Rick Strahl
August 19, 2006

# re: Collection property Hell on an ASP.NET Server Control

Simone, what do you mean 'is useless if you use a strongly typed collection'? If you use a strongly typed collection the default editor will work or you can create a custom editor by overriding the CollectionEditor and using that as your editor (which isn't exactly trivial).

Simone Busoli
August 19, 2006

# re: Collection property Hell on an ASP.NET Server Control

I just mean that you don't need a collection editor when working with STCc. I'm using Collection<T> as the type of my collection property and omitting the attribute

[Editor(typeof(CollectionEditor), typeof(UITypeEditor))]

is working as well in design mode.

# DotNetSlackers: Collection property Hell on an ASP.NET Server Control


Mahmud Hasan
November 27, 2006

# re: Collection property Hell on an ASP.NET Server Control

That's working cool.

Remo
May 21, 2007

# re: Collection property Hell on an ASP.NET Server Control

A collection property has to be read-only. Just delete following line:
"set { _Items = value; }"

Without this line it works fine!

Ahmad El Sheikh
December 23, 2009

# re: Collection property Hell on an ASP.NET Server Control

Hi guys, i have read you comments and its all true i got into this problem to and fortunately i was able to discover that. However, i was stock in another problem that i hope any one of you guys could have an answer for it. The problems is like this consider a Web Server Control just like the above having a collection property again just like the above. trying to edit the control when its placed directly on the designer i.e. not a container control it works fine. But, when i place it in a Panel control the serialization of the property into the CodeDom won't work properly. i am using the IComponentChangeService to notify the designer about the changes done to the property. For example:
componentChangeService.OnComponentChanging(myControl, myControlPropertyDescriptor);
then
componentChangeService.OnComponentChanged(myControl, myControlPropertyDescriptor, oldValue, newValue);


So please do anyone have a solution for this. Note that i have another property of type ITemplate also it did the same problem but when i changed that to PropertyDescripto.SetValue it worked fine in the panel, yeah sure because it has a setter but in the case of the collection i cant because it does not have a setter. In fact even if i add a setter a public one it didn't work for the collection.
I hope to hear from you guys. thanks.

Jaime
March 24, 2010

# re: Collection property Hell on an ASP.NET Server Control

Hello!

Thanks to Simone comment (regarding HtmlGenericControl problem) I could solve a problem that was a headache for the last years.

Cheers
Jaime

Marzban Doctor
January 31, 2012

# re: Collection property Hell on an ASP.NET Server Control

Hi Rick,
I need to create a custom server control with collection properties for the following markup... This server control parses content retrieved from a CMS for tokens delimited by "[[" and "]]" chars. The markup looks like this...
<ww:ContentBlock ID="CB1" runat="server" ContentBlockName="">
    <DataTokens>
        <ww:DataToken ID="CB1DT1" runat="server">
            <%= ListingObject.ListingTitle  %>
        </ww:DataToken>
        <ww:DataToken ID="CB1DT2" runat="server">
            <%= ListingObject.ListingDescription  %>
        </ww:DataToken>
    </DataTokens>
</ww:ContentBlock>


My question is, how do I make the parser bind the "ListingObject" page property from the code-behind to the custom control's collection property???
Thanks,
Marzban

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024