Визуализация вложенных серверных элементов управления - PullRequest
0 голосов
/ 26 марта 2009

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

Я строю навигацию / меню из простой вложенной структуры UL с LI. Родительский объект, который размещается на странице, называется NavController. Имеет коллекцию NavItems.

Так что я в значительной степени позволил NavController обрабатывать создание базового пользовательского интерфейса, создание CSS и JavaScript. Он также создает базовый UL для самого верхнего уровня LI. Исходя из моих исследований и понимания, создание пользовательского интерфейса должно быть сделано в методе CreateChildControls.

Вот мой код:

protected override void CreateChildControls()
{
  Controls.Clear();

  this.Page.RegisterClientJavaScript("~/Resources/Script/SideNav.js");
  _ClientObject = this.GetClientJavaScriptObject("SideNav", this.ClientID);

  Controls.Add(_BaseContainer);

  HtmlGenericControl innerContents = this.BuildBaseContainer();
  this.BuildList(innerContents);

  _ClientObject.AddParameter("BaseContainerID", _BaseContainer.ClientID, true);
  _ClientObject.AddParameter("ImgId", _SideBarTabImg.ClientID, true);
  _ClientObject.AddParameter("SideBarContentsId", _SideBarContents.ClientID, true);

  base.CreateChildControls();
}

Метод BuildList фактически создает LI верхнего уровня. Я не уверен, как этот метод вызывается, но я вижу, что это так. Внутри функции BuildList я добавляю в коллекцию Controls innerContents объекты NavItem.

Прежде всего, это правильно? Размещение другого пользовательского серверного элемента управления внутри UL (с оговоркой, что пользовательский элемент управления в основном отображает LI; подробнее об этом позже)?

CreateChildControls никогда не вызывается для NavItem. Посмотрев в Интернете, мне показалось, что я никогда не звонил в EnsureChildControls. Это сбивает меня с толку, потому что он будет срабатывать только тогда, когда свойство ChildControlsCreated имеет значение false. После запуска это свойство становится истинным. Если у меня есть Text и Href в NavItem и вызывается EnsureChildControls, когда любой из них установлен, то как значение другого будет помещено в любой субэлемент управления?

Просто для того, чтобы забить немного места на экране, вот код, который у меня есть для NavItem:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace AthletesCafe.Web.WebControls.SideNav
{
  [ToolboxData("<{0}:NavItem runat=server></{0}:NavItem>")]
  public class NavItem : ExtendedWebControl
  {
    private string _Text;
    private string _Value;
    private IList<NavItem> _ChildItems = new List<NavItem>();

private HtmlGenericControl _ListItem = new HtmlGenericControl("LI");
private HtmlAnchor _Link = new HtmlAnchor();
private HtmlGenericControl _SubList = new HtmlGenericControl("UL");

public string Text
{
  get
  {
    EnsureChildControls();
    return _Text;
  }

  set
  {
    EnsureChildControls();
    _Text = value;
    _Link.InnerText = _Text;
  }
}

public string Value
{
  get
  {
    EnsureChildControls();
    return _Value;
  }

  set
  {
    EnsureChildControls();
    _Value = value;
    _Link.HRef = _Value;
  }
}

protected override void CreateChildControls()
{
  Controls.Clear();
  Controls.Add(_ListItem);

  _ListItem.Controls.Add(_Link);

  base.CreateChildControls();
}

public NavItem AddChildItem(string text, string url)
{
  EnsureChildControls();

  NavItem newItem = new NavItem();
  newItem.Text = text;
  newItem.Value = url;

  _ChildItems.Add(newItem);
  this.BuildSubList();
  return newItem;
}

private void BuildSubList()
{
  _SubList.Controls.Clear();

  if (_ChildItems.Count > 0)
  {
    if (!_ListItem.Controls.Contains(_SubList))
      _ListItem.Controls.Add(_SubList);

    foreach (NavItem item in _ChildItems)
      _SubList.Controls.Add(item);
  }
}

protected override void Render(HtmlTextWriter writer)
{
  RenderContents(writer);
}

protected override void RenderContents(HtmlTextWriter writer)
{
  _ListItem.RenderControl(writer);
  //base.RenderContents(writer);
}

    public override string ToString()
    {
      EnsureChildControls();
      return _Text + " - " + _Value;
    }
  }
}

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

Пожалуйста, пожалуйста, укажите мне правильный способ сделать это. У меня есть куча этих маленьких элементов управления, которые мне нужно сделать, которые в основном используют тот же подход. Я собираюсь запустить элементарную панель инструментов в ближайшее время, и эта информация поможет!

РЕДАКТИРОВАТЬ - Размещение в коде, который показывает здание списка для уточнения:

HtmlGenericControl list = new HtmlGenericControl("UL");
innerContents.Controls.Add(list);
foreach (NavItem item in _Items)
{
  list.Controls.Add(item);
}

1 Ответ

2 голосов
/ 26 марта 2009

Переопределив CreateChildControls (), вы в основном становитесь ответственными за то, чтобы убедиться, что ваши вложенные элементы управления созданы правильно.

Ваш подход кажется довольно стандартным, однако для ваших простых свойств я не думаю, что вам нужно вызывать EnsureChildControls (). Если вы выбрали это из документации MSDN по этой функции, взгляните еще раз - приведенный ими пример свойства «Текст» - получение текстового значения из одного из его дочерних элементов управления, что означает, что средство доступа к свойствам должно убедиться, что дочерний элемент элементы управления существуют.

Вы не можете гарантировать, что кто-то может получить доступ к вашему элементу управления, поэтому вы должны помещать вызовы EnsureChildControl () перед любым доступом к элементу управления в вашей коллекции элементов управления. В обычном жизненном цикле страницы CreateChildControls () вызывается, когда ASP.net находит способ добавить ваш составной элемент управления на страницу. Этого может не произойти, пока PreRender на первой странице не загрузится, если никто не прикасается к вашему элементу управления, и он не привязывает данные или что-то в этом роде.

При последующих обратных передачах CreateChildControls будет вызываться во время обработки ViewState, или любой код может отключить составной элемент управления, чтобы начать создавать его дочерние элементы управления. Например, FindControl () сделает это автоматически - и это может произойти в OnInit ().

Надеюсь, это поможет. Я думаю, что вы на правильном пути.

...