簡體   English   中英

將動態列添加到ASP.NET Gridview

[英]Adding dynamic columns to an ASP.NET Gridview

我在向GridView動態添加列時遇到問題。 我需要根據DropDownList中的值更改布局 - 即包含的列。 當用戶更改此列表中的選擇時,我需要刪除除第一列之外的所有列,並根據選擇動態添加其他列。

我的標記中只定義了一列 - 第0列,一個模板列,其中我聲明了一個Select鏈接和另一個特定於應用程序的LinkBut​​ton。 該專欄需要始終存在。 在創建ListBoxSelection時,我刪除除第一列之外的所有列,然后重新添加所需的列(在此示例中,我將其簡化為始終添加“標題”列)。 以下是代碼的一部分:

RemoveVariableColumnsFromGrid();
BoundField b = new BoundField();
b.DataField = "Title";
this.gvPrimaryListView.Columns.Add(b);
this.gvPrimaryListView.DataBind();


private void RemoveVariableColumnsFromGrid() {
    int ColCount = this.gvPrimaryListView.Columns.Count;
    //Leave column 0 -- our select and view template column
    while (ColCount > 1) {
        this.gvPrimaryListView.Columns.RemoveAt(ColCount - 1);
        --ColCount;
    }
}

這段代碼第一次運行時,我看到靜態列和動態添加的“標題”列。 但是,下次進行選擇時,第一列將生成為空(其中沒有任何內容)。 我看到了標題欄,我看到它左邊的第一列 - 但是里面沒有生成任何內容。 在調試器中,我可以看到gvPrimaryListView確實仍然有兩列,第一列(索引0)確實是一個模板列。 事實上,該列甚至保留了它的寬度,在下面的標記中設置為165px(用於調試目的)。

有任何想法嗎?

<asp:GridView ID="gvPrimaryListView" runat="server" Width="100%" AutoGenerateColumns="false"
    DataKeyNames="Document_ID" EnableViewState="true" DataSourceID="odsPrimaryDataSource"
    AllowPaging="true" AllowSorting="true" PageSize="10" OnPageIndexChanging="activeListView_PageIndexChanging"
    AutoGenerateSelectButton="False" OnSelectedIndexChanged="activeListView_SelectedIndexChanged"
    Visible="true" OnRowDataBound="CtlDocList_RowDataBound" Font-Size="8pt" Font-Names="Helvetica">
    <Columns>
        <asp:TemplateField ShowHeader="false">
            <ItemTemplate>
                <asp:LinkButton EnableTheming="false" ID="CtlSelectDocRowBtn" runat="server" Text="Select"
                    CommandName="Select" CssClass="gridbutton" OnClick="RowSelectBtn_Click" />
                <asp:ImageButton EnableTheming="false" ID="DocViewBtn" runat="server" ImageUrl="../../images/ViewDoc3.png"
                    CssClass="gridbutton" CommandName="Select" OnClick="DocViewBtn_Click" />
            </ItemTemplate>
            <ItemStyle Width="165px" />
        </asp:TemplateField>
    </Columns>
    <EmptyDataTemplate>
        <asp:Label ID="Label6" runat="server" Text="No rows found." SkinID="LabelHeader"></asp:Label>
    </EmptyDataTemplate>
</asp:GridView>

只是一些額外的信息。

它與第一列無關,而是與它是一個TemplateField這一事實無關。 如果我將一個普通列放在左側(在標記中)並將TemplateField列向右移動,則第一列呈現正常,而(現在第二列)TemplateField列將消失。

另一個奇怪的事情 - 問題不會發生在第一次回發 - 或第二次 - 但它從第三次回發開始,然后繼續進行后續回發。 我很難過。

我最近在gridviews中用動態列征服了silmilar問題,也許這會有所幫助。

首先關閉視圖狀態
其次,在oninit事件中觸發的函數中以編程方式添加列
最后,我使用以下幫助程序類使復選框在RowDataBound事件啟動時實例化。 是的,其中一些是硬編碼的。

這里是所有代碼。 擁有它:) Warrenty原樣,等等等等......

最后,因為我只是讓我的腳濕了DotNet任何提示將不勝感激[IE不要扯我太多:)]。 是的'借用'來自網絡的初始代碼,對不起,我不記得我的頭頂:(

- 在受保護的覆蓋void OnInit中將其關閉

    private void GridViewProject_AddColumns()
    {
        DataSet dsDataSet = new DataSet();
        TemplateField templateField = null;

        try
        {
            StoredProcedure sp = new StoredProcedure("ExpenseReportItemType_GetList", "INTRANETWEBDB", Context.User.Identity.Name);
            dsDataSet = sp.GetDataSet();

            if (sp.RC != 0 && sp.RC != 3000)
            {
                labelMessage.Text = sp.ErrorMessage;
            }

            int iIndex = 0;
            int iCount = dsDataSet.Tables[0].Rows.Count;
            string strCategoryID = "";
            string strCategoryName = "";
            iStaticColumnCount = GridViewProject.Columns.Count;

            // Insert all columns immediatly to the left of the LAST column
            while (iIndex < iCount)
            {
                strCategoryName = dsDataSet.Tables[0].Rows[iIndex]["CategoryName"].ToString();
                strCategoryID = dsDataSet.Tables[0].Rows[iIndex]["CategoryID"].ToString();

                templateField = new TemplateField();
                templateField.HeaderTemplate = new GridViewTemplateExternal(DataControlRowType.Header, strCategoryName, strCategoryID);
                templateField.ItemTemplate = new GridViewTemplateExternal(DataControlRowType.DataRow, strCategoryName, strCategoryID);
                templateField.FooterTemplate = new GridViewTemplateExternal(DataControlRowType.Footer, strCategoryName, strCategoryID);

                // Have to decriment iStaticColumnCount to insert dynamic columns BEFORE the edit row
                GridViewProject.Columns.Insert((iIndex + (iStaticColumnCount-1)), templateField);
                iIndex++;
            }
            iFinalColumnCount = GridViewProject.Columns.Count;
            iERPEditColumnIndex = (iFinalColumnCount - 1); // iIndex is zero based, Count is not
        }
        catch (Exception exception)
        {
            labelMessage.Text = exception.Message;
        }
    }

- 助手班

public class GridViewTemplateExternal : System.Web.UI.ITemplate
{
    #region Fields
    public DataControlRowType DataRowType;
    private string strCategoryID;
    private string strColumnName;
    #endregion

    #region Constructor
    public GridViewTemplateExternal(DataControlRowType type, string ColumnName, string CategoryID)
    {
        DataRowType = type; // Header, DataRow,
        strColumnName = ColumnName; // Header name
        strCategoryID = CategoryID;
    }
    #endregion

    #region Methods
    public void InstantiateIn(System.Web.UI.Control container)
    {
        switch (DataRowType)
        {
            case DataControlRowType.Header:
                // build the header for this column
                Label labelHeader = new Label();
                labelHeader.Text = "<b>" + strColumnName + "</b>";
                // All CheckBoxes "Look Up" to the header row for this information
                labelHeader.Attributes["ERICategoryID"] = strCategoryID;
                labelHeader.Style["writing-mode"] = "tb-rl";
                labelHeader.Style["filter"] = "flipv fliph";
                container.Controls.Add(labelHeader);
                break;
            case DataControlRowType.DataRow:
                CheckBox checkboxAllowedRow = new CheckBox();
                checkboxAllowedRow.Enabled = false;
                checkboxAllowedRow.DataBinding += new EventHandler(this.CheckBox_DataBinding);
                container.Controls.Add(checkboxAllowedRow);
                break;
            case DataControlRowType.Footer:
                // No data handling for the footer addition row
                CheckBox checkboxAllowedFooter = new CheckBox();
                container.Controls.Add(checkboxAllowedFooter);
                break;
            default:
                break;
        }
    }
    public void CheckBox_DataBinding(Object sender, EventArgs e)
    {
        CheckBox checkboxAllowed = (CheckBox)sender;// get the control that raised this event
        GridViewRow row = (GridViewRow)checkboxAllowed.NamingContainer;// get the containing row
        string RawValue = DataBinder.Eval(row.DataItem, strColumnName).ToString();
        if (RawValue.ToUpper() == "TRUE")
        {
            checkboxAllowed.Checked = true;
        }
        else
        {
            checkboxAllowed.Checked = false;
        }
    }
    #endregion
}

通過以下地址在代碼項目中添加動態列到網格視圖(ASP)的最佳解決方案:請查看: http//www.codeproject.com/Articles/13461/how-to-create-columns-dynamically-in -a-網格視圖

diningphilanderer.myopenid.com與我的推薦方法類似。

問題是每次發生回發時都必須重新綁定網格,因此必須重建列。 我喜歡有一個名為BindGrid()的方法,它首先清除列GridView1.Columns.Clear(); 然后以編程方式添加它們,然后設置數據源並調用數據綁定。 確保您為網格禁用了viewstate,並且您有autogeneratecolumns = false;

我今天早些時候發現了這一點: 當插入BoundFields時,GridView中的TemplateField沒有恢復其ViewState

看起來像Microsoft不打算修復的錯誤,因此您必須嘗試上述解決方案之一。 我遇到了同樣的問題 - 我有一些DataBoundFields和一些TemplateFields,並且在回發后,基於TemplateField的列會丟失它們的控件和數據。

我寫了一篇關於類似主題的簡短文章,該文章基於用戶在CheckBoxList控件中選擇的列來處理動態填充GridView列。 希望這對那些尋求簡單演示的人有所幫助如何根據用戶選擇動態生成GridView列?

    void Page_PreRenderComplete(object sender, EventArgs e)
    {
        // TemplateField reorder bug: if there is a TemplateField based column (or derived therefrom), GridView may blank out
        // the column (plus possibly others) during any postback, if the user has moved it from its original markup position.
        // This is probably a viewstate bug, as it happens only if a TemplateField based column has been moved.  The workaround is
        // to force a databind before each response. See https://connect.microsoft.com/VisualStudio/feedback/details/104994/templatefield-in-a-gridview-doesnt-have-its-viewstate-restored-when-boundfields-are-inserted
        //
        // This problem is also happening for grid views inside a TabPanel, even if the TemplateField based columns have not
        // been moved.  Also do a databind in that case.
        //
        // We also force a databind right after the user has submitted the column chooser dialog.
        // (This is because the user could have moved TemplateField based column(s) but ColChooserHasMovedTemplateFields()
        // returns false -- ie when the user has moved all TemplateField based columns back to their original positions.
        if ((!_DataBindingDone && (ColChooserHasMovedTemplateFields() || _InTabPanel)) || _ColChooserPanelSubmitted || _ColChooserPanelCancelled)
            DataBind();

        // There is a problem with the GridView in case of custom paging (which is true here) that if we are on the last page,
        // and we delete all row(s) of that page, GridView is not aware of the deletion during the subsequent data binding,
        // will ask the ODS for the last page of data, and will display a blank.  By PreRenderComplete, it will somehow have
        // realized that its PageIndex, PageCount, etc. are too big and updated them properly, but this is too late
        // as the data binding has already occurred with oudated page variables.  So, if we were on the last page just before
        // the last data binding (_LastPageIndex == _LastPageCount - 1) and PageIndex was decremented after the data binding,
        // we know this scenario has happened and we redo the data binding.  See http://scottonwriting.net/sowblog/archive/2006/05/30/163173.aspx
        // for a discussion of the problem when the GridView uses the ODS to delete data.  The discussion also applies when we
        // delete data directly through ClassBuilder objects.
        if (_LastPageIndex == _LastPageCount - 1 && PageIndex < _LastPageIndex)
            DataBind();

        if (EnableColChooser)
        {
            if (!_IsColChooserApplied)
                ApplyColChooser(null, false, false);
            else
            {
                // The purpose of calling ApplyColChooser() here is to order the column headers properly.  The GridView
                // at this point will have reverted the column headers to their original order regardless of ViewState,
                // so we need to apply our own ordering.  (This is not true of data cells, so we don't have to apply
                // ordering to them, as reflected by the parameters of the call.)

                // If we have already processed column reordering upon the column chooser panel being submitted,
                // don't repeat the operation.
                if (!_ColChooserPanelSubmitted)
                    ApplyColChooser(null, false, true);
            }
        }
    }

我在文檔中的DataControlFieldCollection類下找到了這個小塊。

如果您使用的是GridView或DetailsView控件,則自動創建的DataControlField對象(例如,當AutoGenerateColumns屬性為true時)不會存儲在可公開訪問的字段集合中。 您只能訪問和操作未自動生成的DataControlField對象。

我想答案是在代碼中進行所有列操作,然后你的方法應該可以正常工作。

您可以在開始時定義它們,並根據需要隱藏/顯示它們(使用Visible =“false”或將控件/頁眉/頁腳的CssClass設置為帶有“display:none;”的類,而不是動態添加列。 ? 我在我的一些代碼中使用此方法,包括模板列,沒有任何問題。

對不起,德克爾。 我顯然錯過了幾個關鍵點.. :)

如果這仍然是一個問題,我想知道你的項目模板中有什么不同? 如果您只是在其中放入一些文本,那么刷新頁面幾次,文本是否出現在第一次加載,然后不出現在第二次?

此外,當問題出現時,單元格中是否存在任何html標記,或者它們是否完全為空?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM