DetailsView FindControl() возвращает null после некоторых обратных передач

Я давно работаю с GridViews и DetailsViews, но вчера столкнулся с новым сценарием, в котором совершенно не разбираюсь.

У меня есть GridView с ImageButton (CommandName="Insert"), который изменит режим DetailsView на Insert. После этого я буду искать DropDownList внутри этого DetailsView и динамически добавлять некоторые элементы. Работает нормально, но первый раз, когда я нажимаю кнопку ImageButton. Если я нажму «Отмена» в DetailsView и снова нажму кнопку ImageButton, метод .FindControl() вернет значение null. С какой проблемой жизненного цикла я сталкиваюсь здесь?

Я создал этот пример: (Чтобы запустить его в Visual Studio, просто привяжите DataSource к DetailsView, иначе он не будет отображаться)

Разметка:

<asp:GridView ID="gvCategory" runat="server" OnRowCommand="gvCategory_RowCommand">
    <Columns>
    </Columns>
    <EmptyDataTemplate>
        <asp:ImageButton ImageUrl="~/images/add.png" ID="ibAdd" runat="server" CommandName="Insert" />
    </EmptyDataTemplate>
    </asp:GridView>
    <asp:DetailsView ID="dvCategory" runat="server" Width="150px" AutoGenerateRows="false"
           AutoGenerateInsertButton="True" DataSourceID="LinqDataSource1">
    <Fields>
        <asp:TemplateField HeaderText="foo">
            <InsertItemTemplate>
                <asp:DropDownList ID="ddlCategory" runat="server" Width="150"></asp:DropDownList>
            </InsertItemTemplate>
        </asp:TemplateField>
    </Fields>
    </asp:DetailsView><asp:LinqDataSource ID="LinqDataSource1" runat="server" 
    ContextTypeName="WebApplication1.DataClasses1DataContext" 
    TableName="Categories"></asp:LinqDataSource>

Код программной части:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            this.gvCategory.DataBind();
        } 

    }

    protected void gvCategory_RowCommand(object sender, GridViewCommandEventArgs e)
    {
        if (e.CommandName == "Insert")
        {
            this.dvCategory.ChangeMode(DetailsViewMode.Insert);
            DropDownList _ddlCat = (DropDownList)this.dvCategory.FindControl("ddlCategory");
            if (_ddlCat != null)
            {
                _ddlCat.Items.Clear();
                _ddlCat.Items.Add(new ListItem() { Text = "-- empty --", Value = "-1" });
            }
        }
   }

Я также пытался использовать ItemTemplate, а не InsertItemTemplate, но это приводит к тому же. После использования метода ChangeMode DetailsView.CurrentMode == InsertMode. Единственное, о чем я могу думать, это то, что разметка уже сгенерирована для ItemTemplate, и изменение режима на InsertMode не может повлиять на отображаемую разметку или что-то в этом роде.

У кого-нибудь есть решение для этого? знак равно


person citronas    schedule 07.01.2010    source источник


Ответы (1)


Я думаю, вы на правильном пути. Трудно сказать, не видя всего кода, но в основном каждый раз, когда вы меняете режим рендеринга строки в элементе управления повторителя, вам нужно перепривязать его, чтобы он был повторно визуализирован. Тот факт, что FindControl возвращает NULL, означает только одно: КОНТРОЛЯ НЕТ. Это означает, что он не был отрендерен. Вы можете убедиться в этом, взглянув на иерархию элементов управления.

Итак, в вашем обработчике Cancel вы перепривязываетесь?

person Bryan    schedule 07.01.2010
comment
Кода, который я разместил выше, достаточно, чтобы воспроизвести описанную ситуацию. Я попытаюсь посмотреть, могут ли работать какие-то дополнительные .DataBinds(). - person citronas; 07.01.2010
comment
Явный dvCategory.DataBind() после изменения режима принес решение. Спасибо, чувак, ты не знаешь, как долго я над этим работаю ;) Ты случайно не знаешь, что именно делает вызов .DataBind()? Почему это работает? Заставляет ли DetailsView генерировать новую разметку? - person citronas; 07.01.2010
comment
Что ж, теперь вы задаете сложные вопросы... Честно говоря, не совсем уверен, но вот что я думаю: я не думаю, что рендерится какая-либо разметка, но именно этот вызов запускает создание фактической иерархии элементов управления. А для шаблонных элементов управления создается только ОДИН шаблон за раз: у вас есть либо ItemTemplate, либо EditTemplate, но не оба. Так почему же это работает при первом вызове??? Точно сказать не могу. - person Bryan; 07.01.2010
comment
Кстати, я думаю, мне следовало сказать, что в моем первом ответе было создано, а не визуализировано. - person Bryan; 07.01.2010