Когда элемент управления в программно добавленном TemplateField имеет свое свойство ID? - PullRequest
1 голос
/ 01 апреля 2009

У меня есть TemplateField, который динамически добавляется в пользовательский GridView.

void ITemplate.InstantiateIn(System.Web.UI.Control container)
    {
        switch (_templateType)
        {
            case ListItemType.Header:
                if (this.ParentGridView.ShowDeleteHeaderImage)
                {
                    Image hImg = new Image();
                    hImg.ImageUrl = this.ParentGridView.DeleteHeaderImageUrl;
                    hImg.AlternateText = "Mark for Deletion";
                    container.Controls.Add(hImg);
                }
                else
                {
                    Label l = new Label();
                    l.Text = "Del";
                    container.Controls.Add(l);
                }
                break;
            case ListItemType.Item:
                container.Controls.Add(new CheckBox());
                break;
            case ListItemType.EditItem:
                break;
            case ListItemType.Footer:
                QLImageButton deleteButton = new QLImageButton();
                deleteButton.Settings.ImageId = "cmdQLGVDelete";
                deleteButton.Settings.ImageUrl = this.ParentGridView.DeleteImageUrl;
                deleteButton.CommandName = "Delete";
                container.Controls.Add(deleteButton);
                break;
        }
    }

В ответ на команду сетки (вставка / обновление / удаление) вызывается метод GetRowControls, который перебирает столбцы в конкретной решетке и добавляет каждый из его элементов управления в словарь.

Dictionary<string, WebControl> GetRowControls(GridViewRow row)
...

rowControls.Add(ctrl.ID, (WebControl)ctrl);

...

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

Однако, когда элемент управления является элементом управления TemplateField, добавляемым динамически, ctrl.ID всегда равен null, и поэтому приведенное выше выражение вызывает исключение.

Я посмотрел на это с помощью Reflector, потому что обнаружил, что когда я проверял переменную в ближайшем окне в VS 2005, то есть? Ctrl, ctrl.ID указывал бы значение. С тех пор я установил, что это происходит потому, что в листинге? Ctrl в ближайшем окне вызывается proprty ClientID, а ClientID вызывает EnsureId (), который, в свою очередь, устанавливает ID.

public virtual string ClientID
{
    get
    {
        this.EnsureID();
        string uniqueID = this.UniqueID;
        if ((uniqueID != null) && (uniqueID.IndexOf(this.IdSeparator) >= 0))
        {
            return uniqueID.Replace(this.IdSeparator, '_');
        }
        return uniqueID;
    }
}

Итак, я предполагаю, что ClientID, UniqueId и ID имеют нулевое значение - хотя, как указано выше, простое чтение первых двух вызовет установку всех параметров. Также обратите внимание, что NamingContainer не является нулевым. Это было установлено.

Так что обойти это довольно просто, то есть проверить ctrl.ID == null и, если это так, просто прочитать ctrl.ClientID. И это то, что я сделал, потому что со временем я действительно должен шевелиться. Но я все еще заинтересован в ответе, если кто-нибудь знает его по макушке.

Почему значение идентификатора дочернего элемента управления, динамически добавленного TemplateField, отличается от времени других элементов управления?

Ответы [ 2 ]

2 голосов
/ 02 апреля 2009

Фредди прав.

Вы несете ответственность за установку идентификаторов внутри метода InstantiateIn. И имеет смысл, что ClientID генерирует их автоматически, если не указано иное.

Декларативные элементы управления получают свои идентификаторы, назначенные компоновщиком страниц во время компиляции страницы. Если вы посмотрите на один из временных файлов .cs, сгенерированных в папке «Temporary ASP.NET Files», вы обнаружите что-то вроде этого (раздел с прагмами):

//creating a template field, where CopiledBindableTemplateBuilder is the ITemplate
//and its InstantiateIn = @__BuildControl__control9
@__ctrl.ItemTemplate = new System.Web.UI.CompiledBindableTemplateBuilder(
    new System.Web.UI.BuildTemplateMethod(this.@__BuildControl__control9),
    new System.Web.UI.ExtractTemplateValuesMethod(this.@__ExtractValues__control9));

//and @__BuildControl__control9 calling @__BuildControlButton1
private global::System.Web.UI.WebControls.Button @__BuildControlButton1()
{
    global::System.Web.UI.WebControls.Button @__ctrl;

    @__ctrl = new global::System.Web.UI.WebControls.Button();
    this.Button1 = @__ctrl;
    @__ctrl.ApplyStyleSheetSkin(this);
    @__ctrl.ID = "Button1"; //<-- here it gets an ID
    @__ctrl.Text = "Button";
    return @__ctrl;
}
2 голосов
/ 01 апреля 2009

Дело не в том, что они ведут себя по-разному, но почти всегда, когда вы декларативно добавляете элемент управления, вы сразу устанавливаете идентификатор. Попробуйте добавить на страницу метку без идентификатора, просмотрите коллекцию элементов управления и проверьте ее идентификатор. Она будет иметь значение null (не показывайте ее clientID, так как идентификатор будет заполнен):

<asp:Label runat="server">something</asp:Label>

Также обратите внимание, что если вы запустите его таким образом, вы получите диапазон без идентификатора.

...