事件处理程序仅在第二次点击时被调用。

3
我正在构建一个动态按钮视图,根据数据库中的项目数量以编程方式添加按钮。就像简单的工作流引擎一样。在第一页调用事件处理程序时,它的工作效果符合预期。新页面与新项目一起构建并返回给客户端。在第二个 postback 中,事件处理程序没有被调用,视图保持相同的项目。通过再次点击相同的按钮(第三个 postback),事件处理程序断点得到触发。
我的问题是为什么即使我在每个 postback 上重建页面 (覆盖 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>
5个回答

4
OnInit在调用LoadPostData之前发生,这就是它在第二次点击时起作用的原因。实际上正在处理来自上一次postback的事件。
1. Page_Init 2. LoadViewState 3. LoadPostData 4. Page_Load 5. RaisePostDataChangedEvent 6. RaisePostBackEvent 7. Page_PreRender 8. SaveViewState 9. Page_Render 10. Page_UnLoad
这是Asp.net 1.1事件的简化版本;2.0在其中插入了一些额外的事件,如OnPreInit。但顺序仍然保持不变。
您必须使用Load或之后的事件。某些人选择PreRender,但DataBinding的惯例在Load中。
更新:
我看到你正在动态添加控件到控件树中。这充满了陷阱(但完全可行)。
a)确保您每次加载页面时都添加动态控件,而不仅仅是在postback上。 Postback / viewstate保留状态(即数据),而不是对象。您应该在OnInit(OnLoad也可以,但维护更麻烦)中添加它们。您当前仅在postback上添加,这就是为什么第2个postback起作用(而第一个不起作用)的原因。
b)只初始化动态控件一次,就像您对任何其他控件一样-在[!IsPostBack],在Load中。
-Oisin

所有涉及的控件都是在aspx/ascx中声明的吗?也就是说,您没有在代码中动态添加控件?如果您动态添加控件,情况会更加复杂。 - x0n
啊,我看到你正在这样做。如果你动态地向页面添加控件,你必须确保它们在控件树中始终存在,然后才能处理它们的事件。 - x0n
为了进一步澄清,请确保在OnInit中每次页面加载时(无论PostBack状态如何)将控件添加到控件集合中。但是,仅在第一次[!PostBack]时设置默认值(如果需要)。 - x0n
重写保护方法 void OnInit(EventArgs e) { Presenter = new DynamicGridPresenter(this); if (!IsPostBack) { SetSubmenuVisible = false; Presenter.InitView(); } PrepareView(); } - Xavier Hayoz
  1. 在postpack中,我使用存储在会话中的项目重建了网站。--> 为我的编程添加的按钮添加事件处理程序。--> PrepareView();
  2. 事件处理程序由具有所需命令参数的按钮调用。
  3. 在数据库上执行查询以获取具有相同命令参数的新项目,并存储在会话中
  4. 使用新按钮构建新视图--> PrepareView()
  5. 页面发送回客户端
我需要两次调用PrepareView()。第一次调用是为了知道哪个事件已被触发。第二次调用是为了使用按钮构建新的HTML表格。
- Xavier Hayoz
显示剩余2条评论

4
感谢大家的帮助。我找到了解决方案:
我不知道动态创建的按钮需要一个ID值。我认为Asp会知道哪个按钮被创建了。不幸的是,我错了。似乎.NET比较的是按钮上的ID而不是在ControlTree中的位置。
我添加了以下代码:
new Button{ID = itr.ToString()}
现在当服务器重建站点时,事件处理程序会被触发。
谢谢 x.

1
这种问题几乎总是由于在页面生命周期的错误位置连接事件处理程序而导致的。

我的意思是在onInit方法中添加具有相同项目的事件处理程序。到目前为止,它在重复器、数据网格等方面都运行良好。但现在我不知道该如何解决这个问题。 - Xavier Hayoz
现在你可能需要在不同的地方进行线路连接。几周前我遇到了类似的问题,最终通过尝试在不同的位置进行事件线路连接来解决它。这是一个棘手的问题,因为并不是每个控件的行为都相同。 - Ben Collins
"AddEvents();" 是做什么的?它不是重新绑定所有事件吗?我认为最好适用于(!Page.Ispostback)。 - balint
我在aspx页面上定义了两个按钮(返回和取消)。AddEvent(){ btnCancel.Click+= btnCancel_Click; btnBack.Click+=btnBack_Click; } - Xavier Hayoz

0
如果您在没有声明ID变量的情况下使用它,可能会引起问题。请更改您的ID变量名称。

0

我之前也遇到过类似的问题。我尝试了很多解决方案,但最终发现我的 Web 表单中的一个文本框在回传到服务器时出了问题,导致了混乱。这是一个难以捉摸的 bug,因为我并不打算让我的文本框这样做。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接