15

GridView に列を動的に追加する際に問題が発生しています。DropDownList の値に基づいて、レイアウト (つまり、含まれる列) を変更する必要があります。ユーザーがこのリストの選択を変更すると、最初の列を除くすべてを削除し、選択に基づいて列を動的に追加する必要があります。

マークアップで定義されている列は 1 つだけです。列 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 にはまだ 2 つの列があり、最初の列 (インデックス 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 列を右に移動すると、最初の列が正常にレンダリングされ、(現在は 2 番目の) TemplateField 列が消えます。

もう1つの奇妙なこと-問題は最初のポストバックまたは2番目のポストバックでは発生しませんが、3番目のポストバックで始まり、その後のポストバックが続きます。私は困惑しています。

4

9 に答える 9

5

私は最近、グリッドビューの動的列に関する同様の問題を克服しました。おそらくこれが役立つでしょう。

最初にビューステートをオフにします。次に
、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
}
于 2008-10-30T16:18:37.460 に答える
3

以下のアドレスでコードプロジェクトに配置されたグリッドビュー(ASP)に動的列を追加するための最良のソリューション:チェックしてください:http: //www.codeproject.com/Articles/13461/how-to-create-columns-dynamically-in -グリッドビュー

于 2013-02-01T08:28:47.493 に答える
1

diningphilanderer.myopenid.comには、私がお勧めするものと同様のアプローチがあります。

問題は、ポストバックが発生するたびにグリッドを再バインドする必要があり、その結果、列を再構築する必要があることです。最初に列GridView1.Columns.Clear();をクリアするBindGrid()というメソッドが必要です。次に、それらをプログラムで追加し、データソースを設定してdatabindを呼び出します。グリッドのビューステートが無効になっていて、autogeneratecolumns=falseになっていることを確認してください。

于 2008-10-30T16:26:58.007 に答える
1
    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);
            }
        }
    }
于 2012-01-25T15:50:45.570 に答える
1

CheckBoxList コントロールでユーザーが選択した列に基づいて GridView 列を動的に設定することを扱う、同様のトピックに関する短い記事を書きました。これが簡単なデモンストレーションを探している人に役立つことを願っていますユーザーの選択に基づいて GridView 列を動的に生成する方法は? .

于 2011-06-12T02:50:12.533 に答える
1

今日これを見つけました: GridView の TemplateField では、BoundFields が挿入されたときに ViewState が復元されません

Microsoft が修正する予定のないバグのように見えるため、上記の解決策のいずれかを試す必要があります。私は同じ問題を抱えています-いくつかの DataBoundFields といくつかの TemplateFields があり、ポストバック後、TemplateField ベースの列はコントロールとデータを失います。

于 2008-12-10T19:09:54.280 に答える
0

申し訳ありませんが、デッカー。私は明らかにいくつかの重要なポイントを逃しました..:)

それでも問題が解決しない場合は、アイテムテンプレートの内容に違いがあるのではないでしょうか。そこにテキストを入れてから、ページを数回更新すると、テキストは最初の読み込みで表示され、2回目の読み込みでは表示されませんか?

また、問題が発生した場合、セルにhtmlマークアップがありますか、それとも完全に空ですか?

于 2008-10-30T15:52:11.680 に答える
0

この小さなナゲットは、ドキュメントの DataControlFieldCollection クラスの下で見つけました。

GridView または DetailsView コントロールを使用している場合、自動的に作成される DataControlField オブジェクト (AutoGenerateColumns プロパティが true の場合など) は、パブリックにアクセス可能なフィールド コレクションに格納されません。自動的に生成されない DataControlField オブジェクトにのみアクセスして操作できます。

答えは、すべての列操作をコードで行うことだと思います。そうすれば、あなたのアプローチはうまくいくはずです。

于 2008-10-24T21:08:08.420 に答える
0

列を動的に追加する代わりに、最初に列を定義し、必要に応じて非表示/表示できますか (Visible="false" を使用するか、コントロール/ヘッダー/フッターの CssClass を "display: none;" を使用してクラスに設定します)。 ? テンプレート列を含む一部のコードでこのメソッドを問題なく使用しています。

于 2008-10-29T15:26:13.947 に答える