ASP.NET: обратная передача обрабатывается без запуска событий - PullRequest
1 голос
/ 28 января 2010

У меня есть GridView с динамически созданными кнопками изображений, которые должны запускать командные события при нажатии. Обработка событий в основном работает, за исключением самого первого нажатия кнопки. Затем выполняется обратная передача, но событие не запускается.

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

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

Я прочитал эти посты, но они не соответствуют моей ситуации: Событие ASP.NET LinkButton OnClick не работает на домашней странице , LinkButton не работает на рабочем сервере , Событие ASP.NET Click () не запускается при второй обратной передаче

К деталям: GridView содержит кнопки изображений в каждой строке. Изображения кнопок привязаны к данным. Строки создаются GridView.DataBind (). Чтобы добиться этого, я использовал TemplateField с пользовательской реализацией ItemTemplate. Метод InstantiateIn ItemTemplate создает ImageButton и назначает ему соответствующий обработчик события. Кроме того, событию DataBinding изображения назначается обработчик, который извлекает соответствующее изображение на основе данных соответствующей строки.

GridView помещается в UserControl. UserControl определяет обработчики событий для событий GridView. Код примерно выглядит следующим образом:

private DataTable dataTable = new DataTable();
protected SPGridView grid;

protected override void OnLoad(EventArgs e)
{
    DoDataBind(); // Creates the grid. This is essential in order for postback events to work.
}

protected override void Render(HtmlTextWriter writer)
{
    DoDataBind();
    base.Render(writer); // Renews the grid according to the latest changes
}

void ReadButton_Command(object sender, CommandEventArgs e)
{
    ImageButton button = (ImageButton)sender;
    GridViewRow viewRow = (GridViewRow)button.NamingContainer;
    int rowIndex = viewRow.RowIndex;

    // rowIndex is used to identify the row in which the button was clicked,
    // since the control.ID is equal for all rows.
    // [... some code to process the event ...]
}

private void DoDataBind()
{
    // [... Some code to fill the dataTable ...]

    grid.AutoGenerateColumns = false;

    grid.Columns.Clear();

    TemplateField templateField = new TemplateField();
    templateField.HeaderText = "";
    templateField.ItemTemplate = new MyItemTemplate(new CommandEventHandler(ReadButton_Command));
    grid.Columns.Add(templateField);

    grid.DataSource = this.dataTable.DefaultView;
    grid.DataBind();
}

private class MyItemTemplate : ITemplate
{
    private CommandEventHandler commandEventHandler;

    public MyItemTemplate(CommandEventHandler commandEventHandler)
    {
        this.commandEventHandler = commandEventHandler;
    }

    public void InstantiateIn(Control container)
    {
        ImageButton imageButton = new ImageButton();
        imageButton.ID = "btnRead";
        imageButton.Command += commandEventHandler;
        imageButton.DataBinding += new EventHandler(imageButton_DataBinding);
        container.Controls.Add(imageButton);
    }

    void imageButton_DataBinding(object sender, EventArgs e)
    {
        // Code to get image URL
    }
}

Просто повторюсь: на каждом жизненном цикле сначала выполняется OnLoad, который генерирует Grid с помощью кнопок ImageButtons. Затем события обрабатываются. Поскольку кнопки есть, события обычно работают. После этого вызывается Render, который генерирует Grid с нуля на основе новых данных. Это всегда работает, за исключением самого первого раза, когда пользователь нажимает кнопку изображения, хотя я утверждал, что кнопки сетки и изображения также генерируются, когда страница отправляется пользователю в первый раз.

Надеюсь, что кто-то может помочь мне понять это или предложить лучшее решение для моей ситуации.

Ответы [ 3 ]

3 голосов
/ 29 января 2010

Пара проблем здесь. Во-первых, нет проверки IsPostBack, что означает, что вы привязываете данные при каждой загрузке ... это должно вызывать некоторые проблемы, в том числе события, которые не запускаются. Во-вторых, вы вызываете DoDataBind () дважды при каждой загрузке, потому что вы вызываете его в OnLoad и Render. Почему?

Свяжите данные ОДНАЖДЫ ... и затем снова в ответ на события (при необходимости).

Другая проблема ... не привязывать события к ImageButton в полях шаблона. Это вообще не сработает. Используйте событие ItemCommand и значения CommandName / CommandArgument.

Наконец ... последний вопрос для вас ... Вы провели сравнение (windiff или другой инструмент) HTML-кода, отображаемого всей страницей при первой загрузке, а затем при последующих загрузках? Они точно такие же? Или есть небольшая разница ... в имени элемента управления или ссылке PostBack?

1 голос
/ 29 января 2010

Ну, я думаю, что отправка события происходит после загрузки страницы. В этом случае он попытается запустить элементы управления, созданные при первой попытке привязки данных. Эти элементы управления будут иметь разные идентификаторы, чем когда они будут созданы позже. Я предполагаю, что ASP.NET пытается отобразить входящие события на элемент управления, не найдя элемент управления, и тогда все.

Я рекомендую делать снимки того, что есть в настоящем посте.

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

0 голосов
/ 05 февраля 2010

Так как, на мой взгляд, это частичный ответ, я повторю его так:

  • Если я использую обычные кнопки вместо ImageButtons (в том же месте, то есть все еще использую MyItemTemplate, но создаю экземпляр Button вместо ImageButton в "InstantiateIn", это прекрасно работает.

  • Если я утверждаю, что DoDataBind () всегда выполняется дважды перед отправкой контента клиенту, он отлично работает с ImageButtons.

Все еще озадачен, но что угодно ...

...