Как заставить дочерние элементы управления в Collection вести себя как дочерние элементы управления и / или применять скин? - PullRequest
2 голосов
/ 02 августа 2011

Я пытаюсь создать серверный элемент управления с дочерними элементами управления, которые являются исключительно производными от определенного класса.Дочерние элементы управления в этом случае также являются пользовательскими элементами управления сервера.Это конкретное веб-приложение использует файл темы оформления для применения стилей к этим дочерним элементам управления.

Ранее эти дочерние элементы управления использовались только в качестве дочерних элементов управления другого серверного элемента управления, который допускал любую разметку.Скин работает нормально, хотя с этой моделью есть некоторые недостатки.

Старая модель, которую я все еще должен поддерживать из соображений совместимости, выглядела как

<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 *Элемент управления 1008 * определен следующим образом:

[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; }
}

И SomeFieldControl, и SomeOtherFieldControl наследуются от абстрактного базового класса с именем Field.

Подобная разметка, в которой будет использоваться мой новый серверный элемент управления, будет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 имеет намного больше кода, чем FieldPanel, но некоторые основы:

[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<Field> Fields
    {
        get
        {
            return _fields;
        }

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

Я, конечно, здесь упустил множество методов.У меня есть все рендеринг так, как я хочу , за исключением , что скины не применяются к SomeFieldControl и SomeOtherFieldControl, как они должны быть.Кроме того, при запуске кода значения Parent и Page для SomeFieldControl и SomeOtherFieldControl равны null.Это не тот случай в унаследованном примере.

Я бы хотел не использовать просто ITemplate для сбора внутренних элементов управления, если нет другого способа, так как я полагаюсь на все производные дочерние элементы управленияот Field.Что мне здесь не хватает?Я могу предоставить больше кода по запросу.

Редактировать:

Файл скина (в данном случае Site.skin) имеет запись для каждого из пользовательских Field контролирует а также FieldPanel и FieldTablePanel.Соответствующие части:

<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"
/>

Я внес небольшое изменение в определение FieldPanel выше, добавив правильное имя свойства PanelLabelCssClass, которое является классом CSS, применяемым к определенной метке.Базовый класс Field имеет свойство под названием LabelCssClass, которое снова применяет класс CSS к метке в элементе управления (которая работает, когда элемент управления находится в пределах FieldPanel, но не когда элемент управления находится в разделе <Fields>FieldTablePanel).

Соответствующий 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;
}

Другое Редактирование:

К моему определению класса FieldTablePanel я избавился от своего пользовательского переопределенияControls (который просто в основном вернул коллекцию полей) и добавил:

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

Не повезло.Скины все еще не применяются к элементам управления Field.

Причиной, по которой у меня изначально было переопределение на Controls, была попытка убедиться, что получение Controls вернет ControlCollection, который был всинхронизировать с Fields всегда.Я добавил подобный код в сеттер в своем свойстве Fields (в частности, добавив this.Controls.Clear(); и _fields.ToList().ForEach(this.Controls.Add); в соответствующих местах) без изменений в результатах.Я мог бы попытаться манипулировать добавлением FieldCollection<code> to ensure that when a <code>Field, которое добавляется в коллекцию Control, но я не знаю, поможет ли это.

Еще одна вещь, которую я попытался, это добавить свой внутренний Table как элемент управления для FieldTablePanel , но при этом просто выдавалась ошибка

Было найдено несколько элементов управления с одинаковым идентификатором '...'.Трассировка требует, чтобы элементы управления имели уникальные идентификаторы.
при переходе на страницу с элементом управления.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...