Когда элемент управления в программно добавленном TemplateField имеет свое свойство ID, установленное?

StackOverflow https://stackoverflow.com/questions/703987

Вопрос

У меня есть 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;
        }
    }

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

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

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

...

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

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

Я изучил это с помощью Reflector, потому что обнаружил, что когда я исследовал переменную в окне immediate в VS 2005, т. е.?ctrl, ctrl.Идентификатор будет отображать значение.С тех пор я установил, что это происходит потому, что в списке ?ctrl в окне immediate вызывается 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 не равен null.Это было установлено.

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

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

Это было полезно?

Решение

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

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

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

Другие советы

Фредди прав.

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

Декларативные элементы управления получают свои идентификаторы, назначенные конструктором страниц во время компиляции страницы.Если бы вы посмотрели на один из файлов temp .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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top