模板字段消失

时间:2018-04-09 19:59:19

标签: c# asp.net gridview webforms

我有一个gridview,用于根据下拉列表中的选定值显示记录。

在gridview中,后面的代码中添加了动态数量的绑定字段列,然后是模板字段中的下拉列表和第二个模板字段中的按钮。

问题是,当我点击按钮时,模板字段会消失。

网格视图

<asp:UpdatePanel ID="upnlDetail" runat="server" UpdateMode="Conditional">
    <ContentTemplate>
        <asp:GridView ID="gvDetails" runat="server"
            AutoGenerateColumns="false" 
            SkinID="gridviewGray" 
            CellPadding="3" 
            OnRowCommand="gvDetails_RowCommand" 
            OnRowDataBound="gvDetails_RowDataBound" 
            AllowSorting="true">
            <Columns>
                <asp:TemplateField>
                    <ItemTemplate>
                        <asp:DropDownList ID="ddlStatus" runat="server"
                            AutoPostBack="true" 
                            OnSelectedIndexChanged="ddlStatus_SelectedIndexChanged">
                        </asp:DropDownList>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField>
                    <ItemTemplate>
                        <asp:Button ID="btnSave" runat="server"
                            CommandName="Save" 
                            CommandArgument="<%# ((GridViewRow) Container).RowIndex %>" 
                            Text="Save" />
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
        </asp:GridView>                                
    </ContentTemplate>
</asp:UpdatePanel>

代码背后

while (gvDetails.Columns.Count > 2)  //Don't remove the rightmost columns
{ 
    gvDetails.Columns.RemoveAt(0);
}

gvDetails.Columns.Insert(0, GridViewTools.CreateBoundField(
                                "Request.Amount", "Amount", "Money", 50));
gvDetails.Columns.Insert(0, GridViewTools.CreateBoundField(
                                "Request.CustomerName", "Customer", "comment", 200));
gvDetails.Columns.Insert(0, GridViewTools.CreateBoundField(
                                "Request.BillAccountFormatted", "Account", "text", 100));
gvDetails.Columns.Insert(0, GridViewTools.CreateBoundField(
                                "Request.Id", "Request", "int", 50));

gvDetails.DataSource = dt;
gvDetails.DataBind();

方法GridViewTools.CreateBoundField是一个自定义方法,用于设置我的默认boundfield属性并返回BoundField对象。

public static BoundField CreateBoundField(...){...}

在测试中,gridview根据需要填充初始加载。但是,单击按钮时,RowCommand事件不会触发,两个模板字段都会消失。然后下一个gridview.RowDataBound事件抛出一个空对象错误,因为在该行中找不到下拉列表。

如果删除添加绑定字段[Columns.Insert]的行,则在单击btnSave并且模板字段保持不变时,RowCommand将按预期触发。如果我再次添加一个绑定字段列,则RowCommand不会触发,模板字段也会消失。

有什么建议吗?为什么向gridview添加新列会使预先存在的按钮的RowCommand事件无效并使模板字段消失?

更新 我已经从网格视图声明中删除了模板字段,并将控件添加到绑定字段,但仍然得到相同的结果。显示初始加载,但一旦点击就消失。

我还查看了Page_Unload事件中的网格视图,它仍然包含该点的列,即使它们没有显示在屏幕上。在Page_Unload之后是否可以捕获任何事件?

2 个答案:

答案 0 :(得分:1)

这很有趣。它似乎只在BoundFields被插入时才会发生。将BoundFields添加到Grid的末尾时,它确实有效。

gvDetails.Columns.Add(GridViewTools.CreateBoundField("Request.Amount", "Amount", "Money", 50));

但是你可能想在GridView的末尾使用DropDown和Button。所以你也可以创建那些动态,而不是仅仅向DropDownList添加数据。 所以要做的第一件事是添加2个额外的虚拟BoundField列来保存Button和DropDownList。

gvDetails.Columns.Add(GridViewTools.CreateBoundField("", "DropDownList", "int", 50));
gvDetails.Columns.Add(GridViewTools.CreateBoundField("", "Button", "int", 50));

现在更改RowDataBound事件以添加控件。

protected void gvDetails_RowDataBound(object sender, GridViewRowEventArgs e)
{
    //check if the row is a datarow
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        //create a dropdownlist and add some data
        DropDownList ddl = new DropDownList();
        ddl.ID = "ddlStatus";
        ddl.Items.Add(new ListItem() { Text = "Option 1", Value = "1" });
        ddl.Items.Add(new ListItem() { Text = "Option 2", Value = "2" });
        ddl.Items.Add(new ListItem() { Text = "Option 3", Value = "3" });

        //create a save button
        Button btn = new Button();
        btn.ID = "btnSave";
        btn.CommandName = "save";
        btn.Text = "Save";
        btn.CommandArgument = e.Row.RowIndex.ToString();

        //add the controls to the last 2 cells
        e.Row.Cells[e.Row.Cells.Count - 2].Controls.Add(ddl);
        e.Row.Cells[e.Row.Cells.Count - 1].Controls.Add(btn);
    }
}

但要实现这一点,您需要将DataBind() GridView放在IsPostBack检查之外,但要在其中添加BoundFields。

protected void Page_Load(object sender, EventArgs e)
{
    if (IsPostBack == false)
    {
         //add the boundfields here
    }

    //bind gridview on every postback
    gvDetails.DataSource = dt;
    gvDetails.DataBind();
}

ASPX现在看起来像这样

<asp:GridView ID="gvDetails" runat="server" AutoGenerateColumns="false" 
  OnRowDataBound="gvDetails_RowDataBound" OnRowCommand="gvDetails_RowCommand"></asp:GridView>   

好吧,你现在有一个完全动态创建的GridView。

答案 1 :(得分:1)

在代码中构建所有内容。这不是一个偏好的问题。请阅读Dynamic Web Server Controls and View State

web窗体:

<asp:GridView ID="gvDetails" runat="server"
    AutoGenerateColumns="false" 
    SkinID="gridviewGray" 
    CellPadding="3" 
    OnRowDataBound="OnRowDataBound"
    OnRowCommand="gvDetails_RowCommand"
    AllowSorting="true">
</asp:GridView>

代码背后:

public class GridViewDropDownListTemplate : ITemplate
{
    public void InstantiateIn(Control container)
    {
        DropDownList ddlStatus = new DropDownList();
        ddlStatus.ID = "ddlStatus";
        ddlStatus.Items.Add(new ListItem("Status 1"));
        ddlStatus.Items.Add(new ListItem("Status 2"));
        ddlStatus.Items.Add(new ListItem("Status 3"));
        ddlStatus.Items.Add(new ListItem("Status 4"));
        ddlStatus.AutoPostBack = true;
        ddlStatus.SelectedIndexChanged += ddlStatus_SelectedIndexChanged;
        container.Controls.Add(ddlStatus);
    }

    public void ddlStatus_SelectedIndexChanged(object sender, EventArgs e)
    {
    }
}

public class GridViewButtonTemplate : ITemplate
{
    public void InstantiateIn(Control container)
    {
        Button btnSave = new Button();
        btnSave.ID = "btnSave";
        btnSave.Text = "Save";
        container.Controls.Add(btnSave);
    }
}

public partial class Default : System.Web.UI.Page
{
    object[] data = new[]
    {
        new { Amount = 12500.00, Account = "1234-567-89" },
        new { Amount = 87000.00, Account = "0000-999-88" }
    };

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            BuildBoundFields();
        }

        BuildTemplateFields();
        BindData();
    }

    protected void BuildBoundFields()
    {
        // Amount bound field
        BoundField boundFieldAmount = new BoundField();
        boundFieldAmount.DataField = "Amount";
        boundFieldAmount.HeaderText = "Amount";
        boundFieldAmount.SortExpression = "Amount";
        boundFieldAmount.ItemStyle.Width = Unit.Pixel(100);
        gvDetails.Columns.Add(boundFieldAmount);

        // Account bould field
        BoundField boundFieldAccount = new BoundField();
        boundFieldAccount.DataField = "Account";
        boundFieldAccount.HeaderText = "Account";
        boundFieldAccount.SortExpression = "Account";
        boundFieldAccount.ItemStyle.Width = Unit.Pixel(250);
        gvDetails.Columns.Add(boundFieldAccount);

        // ...
    }

    protected void BuildTemplateFields()
    { 
        // Status template field
        TemplateField statusTemplateField = new TemplateField();
        statusTemplateField.ItemTemplate = new GridViewDropDownListTemplate();
        gvDetails.Columns.Add(statusTemplateField);

        // Save template field
        TemplateField saveTemplateField = new TemplateField();
        saveTemplateField.ItemTemplate = new GridViewButtonTemplate();
        gvDetails.Columns.Add(saveTemplateField);
    }

    protected void BindData()
    {
        gvDetails.DataSource = data;
        gvDetails.DataBind();
    }

    protected void OnRowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            Button btnSave = (Button)e.Row.FindControl("btnSave");
            if (btnSave != null)
            {
                btnSave.CommandArgument = e.Row.RowIndex.ToString();
            }
        }
    }

    protected void gvDetails_RowCommand(object sender, GridViewCommandEventArgs e)
    {
    }
}