代码之家  ›  专栏  ›  技术社区  ›  chiccodoro

ASP.NET:已处理回发,但未激发事件

  •  1
  • chiccodoro  · 技术社区  · 15 年前

    我有一个动态创建图像按钮的网格视图,单击时应该触发命令事件。事件处理基本上可以工作,除了第一次单击按钮。然后,将处理回发,但不会激发事件。

    我试过调试它,在我看来,第一次单击之前和之后执行的代码与其他单击的代码完全相同。(除了第一次单击时不调用事件处理程序。)

    其中有一些特殊之处:触发事件的按钮是通过数据绑定动态创建的,即数据绑定必须在页面生命周期中执行两次:加载一次,以便使按钮存在(否则,事件根本无法处理),渲染前执行一次,以便在EVE之后显示新数据。NTS已处理。

    我读过这些帖子,但它们不符合我的情况: ASP.NET LinkButton OnClick Event Is Not Working On Home Page , LinkButton not firing on production server , ASP.NET Click() event doesn't fire on second postback

    细节: 网格视图在每一行中都包含图像按钮。按钮的图像是数据绑定的。行由gridView.databind()生成。为了实现这一点,我使用了一个定制的itemtemplate实现的templatefield。itemTemplate的instantain方法创建ImageButton并为其分配相应的事件处理程序。此外,将为图像的数据绑定事件分配一个处理程序,该处理程序根据相应行的数据检索适当的图像。

    网格视图放置在一个用户控件上。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,它用imagebuttons生成网格。然后,处理事件。因为按钮在那里,所以事件通常工作。然后,调用render,它根据新数据从头生成网格。这总是有效的,除了第一次用户单击图像按钮,尽管我已经声明网格和图像按钮也是在第一次将页面发送给用户时生成的。

    希望有人能帮助我理解这一点,或者告诉我一个更好的解决方案。

    3 回复  |  直到 15 年前
        1
  •  3
  •   Bryan    15 年前

    这里有几个问题。第一,没有ispostback检查,这意味着您正在对每个负载进行数据绑定…这必然会导致一些问题,包括未触发的事件。其次,在每次加载时调用dodatabind()两次,因为在on load和render中调用它。为什么?

    将数据绑定一次…然后对事件做出反应(如果需要)。

    其他问题…不要将事件绑定到模板字段中的ImageButton。这通常不起作用。使用itemcommand事件和commandname/commandArgument值。

    最后…最后一个问题…您是否在第一次加载时对整个页面呈现的HTML进行了比较(windiff或其他工具),然后进行了后续加载?它们完全一样吗?或者有什么区别…在控件名或回发引用中?

        2
  •  1
  •   Frank Schwieterman    15 年前

    我认为事件调度发生在页面加载之后。在本例中,它将尝试对第一次数据绑定尝试创建的控件运行。此控件的ID与稍后重新创建时不同。我猜ASP.NET正在尝试将传入事件映射到控件,而不是查找控件,然后就是这样。

    我建议捕获实际文章中的内容。

    当涉及到事件绑定和动态创建的控件时,ASP.NET是相当糟糕的。玩得高兴。

        3
  •  0
  •   chiccodoro    15 年前

    因为我认为这是一个部分答案,所以我重新发布:

    • 如果我使用普通按钮而不是ImageButton(在完全相同的位置,即仍然使用MyitemTemplate,但在“实例化”中实例化按钮而不是ImageButton),那么它工作正常。

    • 如果我断言Dodatabind()在将内容发送到客户机之前总是执行两次,那么它可以与ImageButton一起正常工作。

    仍然困惑,但不管怎样…

    推荐文章