35

GridView1.Columns.Count is always zero even SqlDataSource1.DataBind();

But Grid is ok

I can do

for (int i = 0; i < GridView1.HeaderRow.Cells.Count;i++)

I rename request headers here but

GridView1.Columns[i].Visible = false;

I can't use it because of GridView1.Columns.Count is 0.

So how can I hide them ?

Eilon
  • 25,582
  • 3
  • 84
  • 102
cnd
  • 32,616
  • 62
  • 183
  • 313
  • When are you calling GridView1.Columns.Count? If it's too early then the columns haven't been created yet. – Eilon Jan 19 '10 at 06:05
  • If you don't use this column's information or displaying it, why bind it to the `GridView` in the first place. – Eran Betzalel Jan 19 '10 at 06:23
  • 2
    @Eran the GridView's columns might be auto-generated and they want to hide a particular column. For example the table might have ID, FirstName, LastName, but they want to hide the ID column. – Eilon Jan 19 '10 at 06:28
  • because I use hard stored procedure and can't control full loaded information :P think so but that's one of the ways – cnd Jan 19 '10 at 06:31
  • also my grid columns is very dynamic so I need to hide it dynamic. – cnd Jan 19 '10 at 06:35
  • I very want not to create some stored procedure with many many different select operations for each event. I need some trick to check request fields program way. – cnd Jan 19 '10 at 06:55
  • You can use LINQ to select the wanted data, so it doesn't matter how you got it. @Eilon: Of course you can disable the auto-generation and define the columns that you want to display (BTW, ID column should be defined as DataKey, not to be hidden - it's a very common mistake). – Eran Betzalel Jan 20 '10 at 00:01

12 Answers12

49

Try putting the e.Row.Cells[0].Visible = false; inside the RowCreated event of your grid.

protected void bla_RowCreated(object sender, GridViewRowEventArgs e)
{
    e.Row.Cells[0].Visible = false; // hides the first column
}

This way it auto-hides the whole column.

You don't have access to the generated columns through grid.Columns[i] in your gridview's DataBound event.

Jan Jongboom
  • 26,598
  • 9
  • 83
  • 120
  • 6
    That doesn't sound like a good idea. RowCreated will be called several times each time the GridView renders. – Eilon Jan 19 '10 at 06:21
  • It's not that easy. There is no `DataBound` event on a `GridView`, therefore you'll have to make a hook earlier in the binding process, like at `RowCreated` or `RowDataBound`. – Jan Jongboom Jan 19 '10 at 06:26
  • 1
    Actually, GridView very much has a `DataBound` event. – Eilon Jan 19 '10 at 06:42
  • and what must I make there ... how can I cancel adding some column ? – cnd Jan 19 '10 at 06:45
  • In my case I have a combination of "Auto Generated" fields and "Template" fields. If I want to use this snippet to hide for example 3rd column it gives me an error. Hence, I add a conditional statement like **if(e.Row.Cells.Count > 2) e.Row.Cells[2].Visible = false;** and it worked. – Fred Oct 23 '14 at 13:10
  • For me, this does hide the row cells, but the column header is still visible. – dlchambers Aug 06 '16 at 02:20
11

The Columns collection is only populated when AutoGenerateColumns=false, and you manually generate the columns yourself.

A nice work-around for this is to dynamically populate the Columns collection yourself, before setting the DataSource property and calling DataBind().

I have a function that manually adds the columns based on the contents of the DataTable that I want to display. Once I have done that (and then set the DataSource and called DataBind(), I can use the Columns collection and the Count value is correct, and I can turn the column visibility on and off as I initially wanted to.

static void AddColumnsToGridView(GridView gv, DataTable table)
{
    foreach (DataColumn column in table.Columns)
    {
        BoundField field = new BoundField();
        field.DataField = column.ColumnName;
        field.HeaderText = column.ColumnName;
        gv.Columns.Add(field);
    }
}
Steve Hibbert
  • 2,045
  • 4
  • 30
  • 49
10

Note: This solution only works if your GridView columns are known ahead of time.

It sounds like you're using a GridView with AutoGenerateColumns=true, which is the default. I recommend setting AutoGenerateColumns=false and adding the columns manually:

<asp:GridView runat="server" ID="MyGridView"
    AutoGenerateColumns="false" DataSourceID="MySqlDataSource">
    <Columns>
        <asp:BoundField DataField="Column1" />
        <asp:BoundField DataField="Column2" />
        <asp:BoundField DataField="Column3" />
    </Columns>
</asp:GridView>

And only include a BoundField for each field that you want to be displayed. This will give you the most flexibility in terms of how the data gets displayed.

Eilon
  • 25,582
  • 3
  • 84
  • 102
  • 1
    thank you but my datasource provides different columns each time. and thank you for fast answers and correcting my question ! – cnd Jan 19 '10 at 06:38
  • and yes AutoGenerateColumns=true so is there any ways to use dynamic columns with false ? – cnd Jan 19 '10 at 06:39
5

I was having the same problem - need my GridView control's AutogenerateColumns to be 'true', due to it being bound by a SQL datasource, and thus I needed to hide some columns which must not be displayed in the GridView control.

The way to accomplish this is to add some code to your GridView's '_RowDataBound' event, such as this (let's assume your GridView's ID is = 'MyGridView'):

protected void MyGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        e.Row.Cells[<index_of_cell>].Visible = false;
    }
}

That'll do the trick just fine ;-)

3

You have to perform the GridView1.Columns[i].Visible = false; after the grid has been databound.

ddc0660
  • 4,022
  • 2
  • 21
  • 30
3

Try this to hide columns in an ASP.NET GridView with auto-generated columns, both RowDataBound/RowCreated work too.

Protected Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound

    If e.Row.RowType = DataControlRowType.DataRow Or _
        e.Row.RowType = DataControlRowType.Header Then   // apply to datarow and header 

        e.Row.Cells(e.Row.Cells.Count - 1).Visible = False // last column
        e.Row.Cells(0).Visible = False  // first column

    End If
End Sub

Protected Sub GridView1_RowCreated(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowCreated

    If e.Row.RowType = DataControlRowType.DataRow Or _
        e.Row.RowType = DataControlRowType.Header Then

        e.Row.Cells(e.Row.Cells.Count - 1).Visible = False
        e.Row.Cells(0).Visible = False

    End If
End Sub
markmolamhoi
  • 131
  • 1
  • 4
3

In the rowdatabound method for 2nd column

GridView gv = (sender as GridView);
gv.HeaderRow.Cells[2].Visible = false;
e.Row.Cells[2].Visible = false;
Tobi Nary
  • 4,566
  • 4
  • 30
  • 50
guestdj
  • 56
  • 3
  • 1
    @Heather The answer accepted by owner is not correct. It hides only column values not column header. If column header is not hided. previous column content will be shifted to that. It helps for new users – guestdj Jan 13 '16 at 04:29
0

@nCdy: index_of_cell should be replaced by an integer, corresponding to the index number of the cell that you wish to hide in the .Cells collection.

For example, suppose that your GridView presents the following columns:

CONTACT NAME | CONTACT NUMBER | CUSTOMERID | ADDRESS LINE 1 | POST CODE

And you want the CUSTOMERID column not to be displayed. Since collections indexes are 0-based, your CUSTOMERID column's index is..........? That's right, 2!! Very good. Now... guess what you should put in there, to replace 'index_of_cell'??

0

As said by others, RowDataBound or RowCreated event should work but if you want to avoid events declaration and put the whole code just below DataBind function call, you can do the following:

GridView1.DataBind()
If GridView1.Rows.Count > 0 Then
    GridView1.HeaderRow.Cells(0).Visible = False
    For i As Integer = 0 To GridView1.Rows.Count - 1
        GridView1.Rows(i).Cells(0).Visible = False
    Next
End If
Matt Roy
  • 1,455
  • 1
  • 17
  • 27
0

I found Steve Hibbert's response to be very helpful. The problem the OP seemed to be describing is that of an AutoGeneratedColumns on a GridView.

In this instance you can set which columns will be "visible" and which will be hidden when you bind a data table in the code behind.

For example: A Gridview is on the page as follows.

<asp:GridView ID="gv" runat="server" AutoGenerateColumns="False" >
</asp:GridView>

And then in the code behind a PopulateGridView routine is called during the page load event.

protected void PopulateGridView()
{
    DataTable dt = GetDataSource();
    gv.DataSource = dt;
    foreach (DataColumn col in dt.Columns)
    {
        BoundField field = new BoundField();
        field.DataField = col.ColumnName;
        field.HeaderText = col.ColumnName;
        if (col.ColumnName.EndsWith("ID"))
        {
            field.Visible = false;
        }
        gv.Columns.Add(field);
    }
    gv.DataBind();
}

In the above the GridView AutoGenerateColumns is set to False and the codebehind is used to create the bound fields. One is obtaining the datasource as a datatable through one's own process which here I labeled GetDataSource(). Then one loops through the columns collection of the datatable. If the column name meets a given criteria, you can set the bound field visible property accordingly. Then you bind the data to the gridview. This is very similar to AutoGenerateColumns="True" but you get to have criteria for the columns. This approach is most useful when the criteria for hiding and un-hiding is based upon the column name.

0

Similar to accepted answer but allows use of ColumnNames and binds to RowDataBound().

Dictionary<string, int> _headerIndiciesForAbcGridView = null;

protected void abcGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (_headerIndiciesForAbcGridView == null) // builds once per http request
    {
        int index = 0;
        _headerIndiciesForAbcGridView = ((Table)((GridView)sender).Controls[0]).Rows[0].Cells
            .Cast<TableCell>()
            .ToDictionary(c => c.Text, c => index++);
    }

    e.Row.Cells[_headerIndiciesForAbcGridView["theColumnName"]].Visible = false;
}

Not sure if it works with RowCreated().

crokusek
  • 5,345
  • 3
  • 43
  • 61
0

Iterate through the GridView rows and make the cells of your target columns invisible. In this example I want to keeps columns 4-6 visible as is, so we skip those:

foreach (GridViewRow row in yourGridView.Rows)
   {
     for (int i = 0; i < rows.Cells.Count; i++)
     {
        switch (i)
        {
           case 4:
           case 5:
           case 6:
              continue;
        }
        row.Cells[i].Visible = false;
     };
   };

Then you will need to remove the column headers separately (keep in mind that removing header cells changes the length of the GridView after each removal):

grdReportRole.HeaderRow.Cells.RemoveAt(0);