Обработчик события вызывается только при втором клике

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

Моя проблема в том, почему обработчик событий не вызывается, даже если я перестраиваю страницу (переопределяю OnInit()) для каждого сообщения?

Для информации: методы LoadViewWithAlphabeticalDatasource() и LoadViewWithWorkflowItem() делают то же самое, поэтому я удалил один из них в разделе ниже. События добавляются таким же образом.

Код:

<pre>
   namespace EPS.Web.View.Article
   {
       public class DynamicGridView : BasePage, IDynamicGridView
       {


           protected override void OnInit(EventArgs e)
           {
               Presenter = new DynamicGridPresenter(this);
               if (IsPostBack)
               {
                   if (Presenter.Step smallerthan 2)
                   {
                       LoadViewWithAlphabeticalDatasource();
                   }
                   else
                   {
                       LoadViewWithWorkflowItem();
                   }
               }
           }

           [PageMethod]
           protected void Page_Load(object sender, EventArgs e)
           {
               if(!IsPostBack)
               {
                   SetSubmenuVisible = false;
                   Presenter.InitView();
                   PrepareView();
               }
               AddEvents();
               AddLabels();
               PageMethodsEngine.InvokeMethod(this);
           }



           private void Back_Clicked(object sender, EventArgs e)
           {
               Presenter.StepEngine(DynamicGridPresenter.BACK, string.Empty, string.Empty);
               PrepareView();
           }

           private void Cancel_Clicked(object sender, EventArgs e)
           {
               Presenter.StepEngine(DynamicGridPresenter.CANCEL, string.Empty, string.Empty);
               PrepareView();
           }

           private void ForwardString(object sender, EventArgs e)
           {
               Presenter.StepEngine(DynamicGridPresenter.FORWARD, ((LinkButton)sender).CommandArgument, string.Empty);
               PrepareView();
           }

          private void ForwardWorkflowItem(object sender, EventArgs e)
          {
              Presenter.StepEngine(DynamicGridPresenter.FORWARD, string.Empty, ((LinkButton)sender).CommandArgument);
              PrepareView();
          }

          protected void PrepareView()
          {
              phDynamicGridView.Controls.Clear();
              if (Presenter.Step smallerthan 2)
              {
                  LoadViewWithAlphabeticalDatasource();
              }
              else
              {
                  LoadViewWithWorkflowItem();
              }
          }

          private void LoadViewWithWorkflowItem()
          {
              var table = new HtmlTable();
              table.Attributes.Add("class", "tableDynamicGrid");
              int max = GetRowLength(WODatasource.Count);
              int temp = 1;
              int actualPosition = 0;
              int itr = 1;
              var tr = new HtmlTableRow();

              if (WODatasource.Count == 0)
              {
                  phDynamicGridView.Controls.Add(new HtmlTable());
                  return;
              }

              foreach (WorkflowItem s in WODatasource)
              {
                  if (actualPosition biggerOrEqual MaxLength && temp smallerOrEqual max)
                  {
                      table.Rows.Add(tr);
                      actualPosition = 0;
                      temp++;
                      tr = new HtmlTableRow();
                  }


                  actualPosition++;

                  var cell = new HtmlTableCell();
                  // cell.Attributes.Add("class", "cellDynamicGrid");
                  var btn = new LinkButton
                                {
                                    CommandArgument = s.Oid.ToString(),
                                    Text = s.SelectionItem.Name /*, CssClass = "linkButtonDynamicGrid"*/
                                };
                  btn.Click += ForwardWorkflowItem;

                  cell.Controls.Add(btn);
                  tr.Cells.Add(cell);

                  if (itr == WODatasource.Count && temp smallerOrEqual max)
                  {
                      while (itr biggerOrEqual WODatasource.Count && itr smallerThan max*MaxLength)
                      {
                          tr.Cells.Add(new HtmlTableCell());
                          itr++;
                      }
                      table.Rows.Add(tr);
                      phDynamicGridView.Controls.Add(table);
                      return;
                  }
                  itr++;
              }
          }

       }
 </pre>

person Xavier Hayoz    schedule 08.05.2009    source источник


Ответы (5)


OnInit происходит до вызова LoadPostData, и именно поэтому он работает при втором щелчке. На самом деле происходит то, что вы обрабатываете событие из предыдущей обратной передачи.

  1. Страница_Инит
  2. Лоадвиевстате
  3. Загрузитьпостданные
  4. Страница_Загрузка
  5. RaisePostDataChangedEvent
  6. RaisePostBackEvent
  7. Page_PreRender
  8. СохранитьВиевСтате
  9. Page_Render
  10. Страница_Выгрузить

Это упрощенная версия событий из Asp.net 1.1; В версии 2.0 между ними вставлены дополнительные события, например OnPreInit. Хотя порядок остается.

Вы должны использовать событие из Load или более поздней версии. Некоторые люди выбирают PreRender, но соглашение для DataBinding находится в Load.

ОБНОВЛЕНИЕ

Я вижу, вы динамически добавляете элементы управления в дерево элементов управления. Это чревато подводными камнями (но вполне работоспособно).

а) убедитесь, что вы добавляете динамические элементы управления КАЖДЫЙ раз, когда загружается страница, а не только при обратной передаче. Постбэк/состояние просмотра сохраняет СОСТОЯНИЕ (т.е. данные), а не объекты. Вы должны добавить их в OnInit (OnLoad тоже работает, но его сложнее поддерживать). В настоящее время вы добавляете только постбэк, поэтому работает 2-й постбэк (а не первый)

б) инициализируйте динамические элементы управления только ОДИН РАЗ, как и любой другой элемент управления - на [!IsPostBack], в Load.

-Ойсин

person x0n    schedule 08.05.2009
comment
Являются ли все элементы управления декларативными в aspx/ascx? то есть вы не добавляете элементы управления динамически где-то в коде? Если вы динамически добавляете элементы управления, все становится еще сложнее. - person x0n; 08.05.2009
comment
Ах, я вижу, вы делаете это. Если вы динамически добавляете элементы управления на страницу, вы должны убедиться, что они всегда существуют в дереве элементов управления, прежде чем вы сможете обрабатывать для них событие. - person x0n; 08.05.2009
comment
Чтобы уточнить, убедитесь, что вы добавляете элементы управления в коллекцию элементов управления КАЖДЫЙ раз, когда загружается страница (независимо от состояния PostBack), в OnInit. Но устанавливайте только значения ПО УМОЛЧАНИЮ - при необходимости - в первый раз [!PostBack] - person x0n; 08.05.2009
comment
защищенное переопределение недействительным OnInit (EventArgs e) { Presenter = новый DynamicGridPresenter (это); если (!IsPostBack) { SetSubmenuVisible = false; Ведущий.InitView(); } ПодготовитьВид(); } - person Xavier Hayoz; 08.05.2009
comment
1. В postpack я перестраиваю сайт с элементами, сохраненными в сеансе. --› добавляет обработчик событий к моим программно добавленным кнопкам. --› ПодготовитьВид(); 2. Обработчик события вызывается кнопкой с нужным аргументом команды. 3. Запрос выполняется в базе данных для получения новых элементов с тем же аргументом команды и сохраняется в сеансе 4. Новое представление создается с помощью новых кнопок --> PrepareView() 5. Страница отправляется обратно клиенту. Мне нужно вызвать PrepareView() дважды. Первый вызов должен узнать, какое событие было запущено. Второй вызов необходим для создания новой html-таблицы с кнопками. ТИА - person Xavier Hayoz; 08.05.2009
comment
Я действительно не могу тратить время на то, чтобы понять, что вы делаете - в конечном счете, что бы это ни было, это неправильно. Что вам нужно сделать, так это прочитать о правильной методологии и применить ее к вашей проблеме. Возьмите кофе и прочитайте эту замечательную статью на эту тему: aspnet.4guysfromrolla.com /articles/092904-1.aspx - person x0n; 08.05.2009
comment
В любом случае-большое спасибо за вашу поддержку. Я прочитаю статью. Надеюсь, поможет. Уже 2 дня на этом *#¦@~^ выпуске. - person Xavier Hayoz; 08.05.2009

Спасибо всем за помощь. Я нашел решение:

Я не знал, что для динамически создаваемой кнопки требуется значение идентификатора. Я предложил, чтобы Asp знал, какая кнопка создана. К сожалению, я был неправ. Кажется, что .NET сравнивает идентификатор кнопок, а не позицию в ControlTree.

я добавил

new Button{ID = itr.ToString()}

Теперь, когда сервер перестраивает сайт, срабатывает обработчик событий.

с уважением х.

person Xavier Hayoz    schedule 11.05.2009

Проблемы такого рода почти всегда являются результатом подключения обработчиков событий в неправильном месте жизненного цикла страницы.

person Ben Collins    schedule 08.05.2009
comment
Я имею в виду, что добавляю обработчик событий в метод onInit с теми же элементами. До сих пор он отлично работал с повторителем, сеткой данных и т. Д. Но теперь я не знаю, как это решить. - person Xavier Hayoz; 08.05.2009
comment
Теперь вам может понадобиться выполнить подключение в другом месте. У меня была аналогичная проблема пару недель назад, и я в конце концов решил ее, попробовав проводку события в разных местах. Это сложная вещь, потому что не все элементы управления ведут себя одинаково. - person Ben Collins; 08.05.2009
comment
Что делает AddEvents(); делать? Разве это не перепривязка всех событий? Думаю, лучше бы вписался в (!Page.Ispostback) - person balint; 08.05.2009
comment
У меня есть кнопки, определенные на странице aspx (назад и отмена). AddEvent(){ btnCancel.Click+= btnCancel_Click; btnBack.Click+=btnBack_Click; } - person Xavier Hayoz; 08.05.2009

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

person John Fischer    schedule 25.09.2009

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

person Fatih Celen    schedule 13.02.2017