【问题标题】:Gridview Button in TemplateField only fires on second clickTemplateField 中的 Gridview 按钮仅在第二次单击时触发
【发布时间】:2013-03-04 11:09:45
【问题描述】:

在询问之前我已经进行了一些搜索,虽然 this post 很接近,但它不适用于我的场景。

我发现我的模板字段中的“删除”按钮似乎触发了,但点击事件没有触发。然而,当您第二次单击该按钮时,它会按预期工作。

因此,分解代码后,我使用 `SqlDataSource 将我的数据绑定到 GridView

我的页面加载事件开始如下:

if (!Page.IsPostBack)  
{  
    externalUserDataSource.ConnectionString = "some connection string";  
}

我的数据源如下:

<asp:SqlDataSource ID="externalUserDataSource" runat="server" 
    ConflictDetection="CompareAllValues" SelectCommand="uspGetExternalUsersByTeam"
SelectCommandType="StoredProcedure" ProviderName="System.Data.SqlClient">
<SelectParameters>
    <asp:SessionParameter Name="TeamID" SessionField="TeamID" Type="Int32" />
</SelectParameters>
</asp:SqlDataSource>

这是我的GridView 标记:

<asp:GridView ID="gridView" runat="server" AutoGenerateColumns="False" 
    BackColor="White" BorderColor="#3366CC" BorderStyle="None" BorderWidth="1px" 
    CellPadding="4" DataKeyNames="LoginID" DataSourceID="externalUserDataSource" 
    EnableModelValidation="True" OnRowDataBound="GridViewRowDataBound" TabIndex="3">
        <HeaderStyle BackColor="#003399" Font-Bold="True" ForeColor="White" />
        <FooterStyle BackColor="#99CCCC" ForeColor="#003399" />
        <PagerStyle BackColor="#99CCCC" ForeColor="#003399" HorizontalAlign="Left" />
        <RowStyle BackColor="LightGoldenrodYellow" />
        <SelectedRowStyle BackColor="#009999" Font-Bold="True" ForeColor="#CCFF99" />
        <Columns>
            <asp:BoundField DataField="RowID" HeaderText="Row ID" ReadOnly="True" 
                SortExpression="RowID" Visible="False" />
            <asp:BoundField DataField="LoginID" HeaderText="Login ID" ReadOnly="True" 
                SortExpression="LoginID" Visible="False" />
            <asp:BoundField DataField="EmailAddress" HeaderText="Email Address" 
                ItemStyle-VerticalAlign="Bottom" ReadOnly="True" SortExpression="AssociateName"/>
            <asp:BoundField DataField="TeamID" HeaderText="Team ID" ReadOnly="True" 
                SortExpression="TeamID" Visible="False" />
            <asp:CheckBoxField DataField="HasFIAccess" 
                 HeaderText="Has Access to&lt;br /&gt;Funding&lt;br/&gt;Illustrator" 
                 ItemStyle-HorizontalAlign="Center" ItemStyle-VerticalAlign="Bottom" 
                 ReadOnly="True"/>
            <asp:CheckBoxField DataField="HasALTAccess" 
                 HeaderText="Has Access to&lt;br /&gt;Asset Liability&lt;br/&gt;Tracker" 
                 ItemStyle-HorizontalAlign="Center" ItemStyle-VerticalAlign="Bottom"
                 ReadOnly="True"/>
            <asp:CheckBoxField DataField="HasFIAAccess" 
                 HeaderText="Has Access to&lt;br /&gt;Funding&lt;br/&gt;Illustrator App" 
                 ItemStyle-HorizontalAlign="Center" ItemStyle-VerticalAlign="Bottom"
                 ReadOnly="True"/>                    
            <asp:TemplateField>
            <ItemTemplate>
                <asp:Button runat="server" CssClass="additionsRow" ID="btnDeleteExternalUser" OnClick="DeleteExtUserButtonClick" 
                    CausesValidation="False" Text="Delete" 
                    CommandArgument='<%#Eval("TeamID") + "," + Eval("LoginID") + "," + Eval("EmailAddress") + "," + Eval("HasALTAccess")%>'/>                            
            </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>

因此,您可以看到我在事件中使用的按钮中传递了一些信息,以确保删除正确的数据(这就是为什么我不能使用ButtonField,如上面的链接中所建议的那样) .

谜题的最后一部分是GridView的数据绑定事件:

        protected void GridViewRowDataBound(object sender, 
                                        GridViewRowEventArgs e)
    {
        // if rowtype is not data row...
        if (e.Row.RowType != DataControlRowType.DataRow)
        {
            // exit with no further processing...
            return;
        }

        // get the ID for the selected record...
        var selectedId = DataBinder.Eval(e.Row.DataItem, "RowID").ToString();

        // create unique row ID...
        e.Row.ID = string.Format("ExtUserRow{0}", selectedId);

        // find the button delete for the selected row...
        var deleteButton = (Button)e.Row.FindControl("btnDeleteExtUser");

        // get the email address for the selected record...
        var selectedUser = DataBinder.Eval(e.Row.DataItem, "EmailAddress").ToString();

        // define the message text...
        var messageText = string.Format("OK to delete {0}?",
                                        selectedUser.Replace("'", "\\'")); 

        // add attribute to row delete action...
        this.AddConfirmMessage(deleteButton, messageText);
    }  

AddConfirmMessage 只是简单地将 onclick 属性分配给控件以确保用户必须确认删除。

现在,在每种情况下都会弹出消息“OK to delete abc@xyz.com?”,但如前所述,分配给“delete”按钮的事件直到按钮被第二次点击。

奇怪的是,我从另一个页面获取了这段代码并进行了相应的修改,尽管那里没有这个问题:

        protected void DeleteExtUserButtonClick(object sender, 
                                            EventArgs e)
    {
        // get the buton which was clicked...
        var button = (Button)sender;

        // break the delimited array up...
        string[] argumentArray = button.CommandArgument.Split(',');

        // store the items from the array...
        string teamId = argumentArray[0];
        string loginId = argumentArray[1];
        string emailAddress = argumentArray[2];
        string hasAltAccess = argumentArray[3];

        using (var conn = new SqlConnection(Utils.GetConnectionString()))
        {
            // create database command...
            using (var cmd = new SqlCommand())
            {
                // set the command type...
                cmd.CommandType = CommandType.StoredProcedure;

                // set the name of the stored procedure to call...
                cmd.CommandText = "uspDeleteExternalUser";

                // create and add parameter to the collection...
                cmd.Parameters.Add(new SqlParameter("@TeamId", SqlDbType.Int));

                // assign the search value to the parameter...
                cmd.Parameters["@TeamId"].Value = teamId;

                // create and add parameter to the collection...
                cmd.Parameters.Add(new SqlParameter("@LoginId", SqlDbType.VarChar, 50));

                // assign the search value to the parameter...
                cmd.Parameters["@LoginId"].Value = loginId;

                // set the command connection...
                cmd.Connection = conn;

                // open the connection...
                conn.Open();

                // perform deletion of user...
                cmd.ExecuteNonQuery();
            }
        }

        // bind control to refresh content...
        ExtUsersGrid.DataBind();
    }

我是否遗漏了一些明显的东西?如果有更好的方法,我很乐意修改。

编辑 1:根据下面的讨论,我修改了以下内容:

  • 删除了ButtonItemOnclick 事件属性;
  • 按照以下建议设置CommandNameCommandArgument,并更新DataKeyNames 以使用数据中唯一的ID RowID;
  • GridView 分配了RowCommand 事件;
  • 将删除代码分配给RowCommand 事件。

进行这些更改后,它仍然会在第二次点击时触发行事件代码。

编辑 2:仅供参考 - 我现在删除了 SqlDataSource 和相关的代码/引用,并创建了一个填充数据集的过程,该过程在 Page_Load 上调用(在!Page.IsPostBack 括号)。我开始在下面进行更改以使用 RowCommand 事件,但它们仍然导致相同的问题(即该按钮只会在第二次单击时触发)。因为使用RowCommand 意味着将BoundFields 转换为ItemTemplates,所以我回到了按钮单击事件,因为毫无意义地进行所有这些更改似乎毫无意义。如果其他人可以帮助我理解为什么它只在第二次点击时触发,将不胜感激。

【问题讨论】:

  • 您似乎没有像示例中那样向 deleteButton 添加事件处理程序。
  • 是的,抱歉,我注意到了这一点并更新了我的代码 - 我试图在代码中添加事件,但在发布我的问题之前忘记将其添加回来。代码现在是最新的。
  • 如果我也分享我的删除按钮事件代码可能会很有用,所以会在下面添加一个答案。
  • 那么你在哪里添加事件处理程序?也许我在这里挑剔,但似乎您仍然没有将 DeleteExtUserButtonClick 添加到按钮。
  • 在 Button 字段中的代码是 OnClick="DeleteExtUserButtonClick" 但实际上,这已经过去了,因为我已经通过启动 RowCommand 事件来使用 Praveen 建议的方法,将网格填充为第一个回发,但我仍然有同样的问题。它与哪个按钮无关,所以我可以在第 1 行删除,你会看到看起来像回发但没有触发代码的内容,然后在第 2 行单击删除,你会得到相同的结果。直到第二次单击,RowCommand 的代码才会触发。所以虽然我有更好的代码,但它仍然给我同样的问题。

标签: c# asp.net gridview templatefield


【解决方案1】:

好的,令人沮丧的是,这是由于某些未知原因的代码在其他地方工作。
在DataBound事件中,有两行代码:

        // get the associate name for the selected record...
        var selectedId = DataBinder.Eval(e.Row.DataItem, "RowID").ToString();
        // create unique row ID...
        e.Row.ID = string.Format("ExtUserRow{0}", selectedId);  

以编程方式将 ID 应用于行的过程似乎破坏了数据和事件之间的联系。
通过删除这两行代码,它可以按预期工作。

【讨论】:

    【解决方案2】:

    你可以做这样的事情。

    像这样将CommandName 属性添加到您的GridView。还要注意CommandArgument 属性的变化:

    <asp:TemplateField>
        <ItemTemplate>
            <asp:Button runat="server" CssClass="additionsRow" ID="btnDeleteExtUser"  
                        CausesValidation="False" Text="Delete" 
                        CommandName="OnDelete"  
                        CommandArgument='<%# Container.DisplayIndex %>" '                              
    </ItemTemplate>
    </asp:TemplateField>
    

    后面的代码看起来像这样。请注意,我使用的是GridviewRowCommand 事件。

    protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
    {
        if(e.CommandName == "OnDelete")
        {
            int rowIndex = Convert.ToInt32(e.CommandArgument);
            // now you got the rowindex, write your deleting logic here.
            int ID = Convert.ToInt32(myGrid.DataKeys[rowIndex]["ID"].Value);
            // id will return you the id of the row you want to delete 
            TextBox tb = (TextBox)GridView1.Rows[rowIndex].FindControl("textboxid");
            string text = tb.Text;
            // This way you can find and fetch the properties of controls inside a `GridView`. Just that it should be within `ItemTemplate`.
        }
    } 
    

    注意:在您的 GridView 中提及 DataKeyNames="ID"。 “ID”是表的主键列。

    您是否在页面加载时绑定GridView?如果是,则将其移至!IsPostBack 块,如下所示:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            GridView1.DataSource = yourDataSource;
            GridView1.DataBind();           
        } 
    }
    

    【讨论】:

    • 好的,谢谢...但是什么是 Container.DisplayIndex 以及如何用我需要的数据填充它?我认为仍然需要数据绑定事件来设置属性和行 ID?
    • 另外,我的删除事件正在数据库上运行另一个存储过程来删除用户,这就是我在 commandargument 属性中传递数据的原因。我想当我了解 Container.DisplayIndex 是什么时,它可能会到位。谢谢。
    • GridView 显然会有很多行。因此,在 CommandArgument 上设置的 Container.DisplayIndex 将给出单击一行的按钮事件的 rownumber/rowindex。这可以进一步用于获取要删除的行的 ID。
    • 好的,但是我看不出这对我有什么帮助?数据正在正确填充,虽然只是第二次,但该事件会触发并从系统中删除正确的数据,因此查找该行没有任何好处 - 它试图了解按钮事件不触发的原因。还是我错过了什么(这不会让我感到惊讶!)?
    • 就像我在回答中所说的那样,这是执行上述操作的另一种方法。我肯定会解决您面临的问题。因为我认为当 asp.net gridview 具有诸如 CommandName 和 CommandArgument 之类的良好功能时,从 gridview 的模板字段中调用按钮单击事件会产生不必要的开销。
    猜你喜欢
    • 1970-01-01
    • 2012-04-03
    • 2021-03-14
    • 1970-01-01
    • 2018-05-24
    • 2014-04-21
    • 1970-01-01
    • 1970-01-01
    • 2018-07-22
    相关资源
    最近更新 更多