【问题标题】:Template field disappears模板字段消失
【发布时间】:2018-09-19 07:32:00
【问题描述】:

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

在 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 事件无效并使模板字段消失?

更新 我已经从 Grid View 声明中删除了模板字段,并将控件添加到绑定字段,但仍然得到相同的结果。初始加载时显示,但单击后消失。

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

【问题讨论】:

  • 是您帖子中关于页面加载的代码吗?
  • fwiw, here's 一个非常老的帖子,有类似的问题。一个人说这是一个无法修复的错误,另一个人的解决方案类似于 VDWWD 的。 “我的解决方案是使用 Columns.Add 方法添加我的动态列,然后还以编程方式添加应遵循的列(而不是在 aspx html 中定义它们)。”
  • 后面的代码在页面加载事件调用的方法中。页面加载后一切都按预期显示。

标签: c# asp.net gridview webforms


【解决方案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);
    }
}

但要使其正常工作,您需要将 GridView 的 DataBind() 放在 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。

【讨论】:

  • 绑定字段是插入到左侧还是添加到右侧的行为是相同的。据我所知,Buttons 和 DropDownLists 必须在 TemplateField 中。我从未见过显示 BoundField 中包含的 Button 的示例。我也考虑过动态生成 Button 和 DDL,但由于这些控件不会随其余内容而改变,因此它似乎比它的价值更麻烦。
  • 插入的是,添加的是否。添加后,它们位于 TemplateFields 后面,然后它们会持续存在。最终 BoundField 生成 Cells。您可以像使用任何其他控件一样使用它们。
  • 不,添加绑定字段后模板字段仍然消失,使所有绑定字段(插入和添加)彼此相邻。
  • 奇怪,它们仍然存在于我的本地机器上。
  • 我会尝试将 ddl/btn 添加到绑定字段中,看看是否会有所不同。
【解决方案2】:

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

网络表单:

<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)
    {
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多