开发者

How do I make child controls in Collection behave as child controls and/or get skin applied?

I am trying to create a server control with child controls that are exclusively derived from a particular class. The child controls in this case are all custom server controls also. This particular web application uses a Skin file to apply styles to these child controls.

Previously, these child controls were only used as child controls of another server control that allowed any markup. The skin works fine, though there are some deficiencies with this model.

The old model -- which I must still support for legacy compatibility reasons -- looked something like

<myns:FieldPanel ID="SomeId" runat="server" LabelText="SomeLabelText">
    <myns:SomeFieldControl ID="SomeControlName" runat="server" SomeProperty="false" />
    <myns:SomeOtherFieldControl ID="AnotherControl" runat="server" SomeProperty="false">
        <Items>
            <asp:ListItem Text="One" Value="1" />
            <asp:ListItem Text="Dos" Value="2" />
            <asp:ListItem Text="Trois" Value="3" />
        </Items>
    </myns:SomeOtherFieldControl>
</myns:FieldPanel>

The FieldPanel control is defined like

[ParseChildren(false)]
public class FieldPanel : WebControl
{
    public override void RenderBeginTag(HtmlTextWriter writer)
    {
        // some rendering
    }

    public override void RenderEndTag(HtmlTextWriter writer)
    {
        // some more rendering
    }

    public string PanelLabelCssClass { get; set; }

    public string LabelText { get; set; }
}

Both SomeFieldControl and SomeOtherFieldControl inherit from an abstract base class called Field.

Similar markup that would use my new server control would be

<myns:FieldTablePanel ID="AnotherId" runat="server" LabelText="OtherLabelText">
    <Fields>
        <myns:SomeFieldControl ID="SomeControlName" runat="server" SomeProperty="false" />
        <myns:SomeOtherFieldControl ID="AnotherControl" runat="server" SomeProperty="false">
            <Items>
                <asp:ListItem Text="One" Value="1" />
                <asp:ListItem Text="Dos" Value="2" />
                <asp:ListItem Text="Trois" Value="3" />
            </Items>
        </myns:SomeOtherFieldControl>
     </Fields>
</myns:FieldTablePanel>

FieldTablePanel has a lot more code than FieldPanel, but some basics:

[DefaultProperty(null)]
[ParseChildren(true)]
public class FieldTablePanel : FieldPanel, INamingContainer
{
    private FieldCollection _fields;
    private Table _innerTable;

    public class FieldCollection : Collection<Field>, INamingContainer
    {
        // mainly standard Collection methods that I have to do something special with
    }

    [Bindable(false)]
    [DefaultValue(null)]
    [TemplateContainer(typeof(FieldCollection))]
    [PersistenceMode(PersistenceMode.InnerProperty)]
    // Note that FieldCollection does not work here
    public Collection开发者_JAVA技巧<Field> Fields
    {
        get
        {
            return _fields;
        }

        set
        {
            _innerTable.Rows.Clear();
            _fields = new FieldCollection(_innerTable, Page, value);
        }
    }
}

I left out a lot of methods here, of course. I have everything rendering the way I want except that the skins are not applied to SomeFieldControl and SomeOtherFieldControl as they should be. Further, when running the code, both Parent and Page for SomeFieldControl and SomeOtherFieldControl are null. This is not the case in the legacy example.

I would like to avoid just using ITemplate for the collection of inner controls unless there is no other way, since I am relying on all the child controls being derived from Field. What am I missing here? I can provide more code on request.

Edit:

The skin file (Site.skin, in this case) has an entry for each of the custom Field controls as well as FieldPanel and FieldTablePanel. The relevant portions:

<myns:FieldPanel runat="server"
  PanelLabelCssClass="formPanelLabel"
  Width="100%"
/>

<myns:FieldTablePanel runat="server"
  PanelLabelCssClass="formPanelLabel"
  Width="100%"
/>

<myns:SomeFieldControl runat="server"
  LabelCssClass="formFieldLabel"
  ResourceClassKey="CommonResource"
  RequiredErrorMessageResourceKey="RequiredMessageFormat"
/>

<myns:SomeOtherFieldControl runat="server"
  LabelCssClass="formFieldLabel"
  RequiredErrorMessageResourceKey="RequiredMessageFormat"
  ResourceClassKey="CommonResource"
  ChooseOneResourceKey="ChooseOneOption"
  NoneResourceKey="NoneOption"
/>

I did make a slight edit to the definition of FieldPanel above to include the correct property name PanelLabelCssClass, which is a CSS class that gets applied to a particular label. The Field base class has a property called LabelCssClass which, again, applies a CSS class to a label within the control (which works when the control is within FieldPanel but not when the control is within the <Fields> section of FieldTablePanel).

The relevant CSS:

.formFieldLabel
{
    font-family: Tahoma, Verdana, Arial, Helvetica, san;
    font-size: smaller;
}

.formPanelLabel
{
    font-family: Tahoma, Verdana, Arial, Helvetica, san;
    color: #666666;
    font-size: x-small;
}

Another Edit:

To my FieldTablePanel class definition, I got rid of my custom override of Controls (which just basically returned the field collection) and added:

protected override void OnInit(EventArgs e)
{
    if (_fields != null)
    {
        _fields.ToList<Field>().ForEach(this.Controls.Add);
    }
}

No luck. The skins are still not being applied to the Field controls.

The reason I initially had an override on Controls was to try to ensure that getting Controls would return a ControlCollection that was in sync with Fields at all times. I added similar code to the setter in my Fields property (specifically, adding this.Controls.Clear(); and _fields.ToList().ForEach(this.Controls.Add); at appropriate places) with no change in results. I could try manipulating the FieldCollection to ensure that when a Field is added that it is added to the Control collection, but I don't know whether that would help.

One more thing I did try was adding my inner Table as a Control of FieldTablePanel, but doing so just gave me the error

Multiple controls with the same ID '...' were found. Trace requires that controls have unique IDs.
when going to the page with the control.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜