This question already has answers here:
GridView Hide Column by code
(13 answers)
Closed 8 years ago.
I have gridview and I want to hide a column after databind to gridview but I get the error below.
"Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index"
My C# code is below,
protected void grid_all_posts_DataBound(object sender, EventArgs e)
{
if (grid_all_posts.Columns[1].Visible)
{
grid_all_posts.Columns[1].Visible = false;
}
}
// Read all posts and fill gridview
//////////////////////////////////////////////////
DbCommand dbCommand2;
dbCommand2 = db.GetStoredProcCommand("SP_Select_News");
db.AddInParameter(dbCommand2, "UserId", DbType.Guid, new Guid(Session["UserId"].ToString().Trim()));
DataSet ds = db.ExecuteDataSet(dbCommand2);
grid_all_posts.DataSource = ds;
grid_all_posts.DataBind();
//////////////////////////////////////////////////
My ASPX code,
<asp:gridview runat="server" ID="grid_all_posts" OnRowDataBound="grid_all_posts_DataBound"></asp:gridview>
What do you think the problem is? How I can hide the first column
Try like below it will work....
DbCommand dbCommand2;
dbCommand2 = db.GetStoredProcCommand("SP_Select_News");
db.AddInParameter(dbCommand2, "UserId", DbType.Guid, new Guid(Session["UserId"].ToString().Trim()));
DataSet ds = db.ExecuteDataSet(dbCommand2);
grid_all_posts.DataSource = ds;
grid_all_posts.DataBind();
**//after Databind Write the below code**
if (grid_all_posts.Columns.Count > 0)
grid_all_posts.Columns[0].Visible = false;
else
{
grid_all_posts.HeaderRow.Cells[0].Visible = false;
foreach (GridViewRow gvr in grid_all_posts.Rows)
{
gvr.Cells[0].Visible = false;
}
}
A simple and versatile approach for this has been bugging me for ages - something that does not require any kind of column counting, I eventually found it today; DataControlFieldCell.ContainingField.HeaderText
Private Sub GridView_RowDataBound(sender As Object, e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView.RowDataBound
For Each r As GridViewRow In GridView.Rows
If r.RowType = DataControlRowType.DataRow Then
For Each c As DataControlFieldCell In r.Cells
Dim h As String = c.ContainingField.HeaderText
If h <> "ColumnName" Then c.ContainingField.Visible = False
If IsNumeric(c.Text) Then c.Text = Format(CInt(c.Text), "#,##0")
Next
End If
Next
End Sub
I loop through the DataControlFieldCells as I perform some formatting on the values in my fields as well (as illustrated above) but you could just loop through the header I imagine if you wanted to cut it down further still.
See msdn for more details.
Related
I implemented sorting on my GridView with a DataTable as DataSource by using code from this MSDN link. However, my grid sorts for the first time when I click any column, and after that it does not sort on clicking any other column.
Code in the PageLoad() event -
if (!Page.IsPostBack)
{
HView hv = new HView ();
DataTable HTable = new DataTable("hTable");
HTable = hv.FillTable();
Session["hTable"] = HTable;
GridView2.DataSource = Session["hTable"];
GridView2.DataBind();
}
Code in the Sorting event -
protected void GridView2_Sorting(object sender, GridViewSortEventArgs e)
{
DataTable notesDT = Session["hTable"] as DataTable;
if (notesDT != null)
{
notesDT.DefaultView.Sort = e.SortExpression + " " + GetSortDirection(e.SortDirection);
GridView2.DataSource = Session["hTable"];
GridView2.DataBind();
}
}
Does anybody have an idea of what I may be doing wrong?
EDIT: I just realized this. If I select a particular row, I have another view that gets populated with details about that row. When I view some rows details first before trying to sort any columns, then sorting works perfectly fine, any number of times. However, if I try to sort before selecting a row, it works only once.
You are using the DataTable as DataSource in the sorting event, but you should use the sorted view instead. Sorting the view won't change the sort order of the data in the table, just the order in the view.
protected void GridView2_Sorting(object sender, GridViewSortEventArgs e)
{
DataTable notesDT = Session["hTable"] as DataTable;
if (notesDT != null)
{
notesDT.DefaultView.Sort = e.SortExpression + " " + GetSortDirection(e.SortDirection);
GridView2.DataSource = notesDT.DefaultView;
GridView2.DataBind();
}
}
Edit: Although that i've just noticed that you're using rhe same code from MSDN.
You could also try to create a new DataTable from the view:
GridView2.DataSource = notesDT.DefaultView.ToTable(true);
You don't need stored the data table into a session. Actually putting the entire data table into session is not a good idea at all. Any particular reason for that?
Hey guys, I have an ASP.NET GridView bound to a DataView that contains a DataTable. I'm not using a DataAdapter.
I want to update a row in my DataTable, so I do this:
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
DataView dv = (DataView)Session["My_DataTable"];
DataTable dt = dv.Table;
int rowIndex = GridView1.Rows[e.RowIndex];
dt.Rows[rowIndex]["FirstName"] = thenewfirstname;
dt.Rows[rowIndex]["MI"] = thenewmi;
dt.Rows[rowIndex]["LastName"] =thenewlastname;
Session["My_DataTable"] = dv;
//Reset the edit index.
GridView1.EditIndex = -1;
//Bind data to the GridView control.
GridView1.DataSource = Session["My_DataTable"];
GridView1.DataBind();
}
The underlying DataView/DataTable is changed correctly, but the GridView contains both the old row before the edit, and the new row after the edit (that is, it adds an additional row with the new edits!).
For example, if we have :
...
Sammy S Samerson
...
and change it to Sammy E Samerson the gridview says :
...
Sammy S Samerson
Sammy E Samerson
...
How do I fix this, what did I do wrong?
A lot of strange things were happening.
The gist of all of the Bad Things was the DataView - because things were being reordered, the index of the GridView, and the index of the DataTable in the DataView weren't matching up. The DataTable had to be looped through untill the correct just-edited record was found.
Did you check the row index of the editing row. int rowIndex = GridView1.Rows[e.RowIndex]; you can directly use the e.RowIndex.
My Suggestion is to get the row by using any key field of the table.
for example
DataRow[] customerRow =
dataSet1.Tables["Customers"].Select("CustomerID = 'ALFKI'");
customerRow[0]["CompanyName"] = "Updated Company Name";
customerRow[0]["City"] = "Seattle";
You can get the row values by using the cell position. Or use datakeynames
for example :
string courseid = GridView1.Rows[e.RowIndex].Cells[3].Text;
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 ?
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.
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);
}
}
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.
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 ;-)
You have to perform the GridView1.Columns[i].Visible = false; after the grid has been databound.
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
In the rowdatabound method for 2nd column
GridView gv = (sender as GridView);
gv.HeaderRow.Cells[2].Visible = false;
e.Row.Cells[2].Visible = false;
#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'??
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
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.
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().
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);
I have seen several tutorials on how to achieve this.
However in my opinion they require a lot of prior knowledge on how to programatically refer to each item.
Does anyone have a link to or can create a relatively basic example of how to achive a running total in the footer for an ASP:Gridview?
This is what I use:
protected void InvoiceGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
var invoice = (Invoice) e.Row.DataItem;
if (e.Row.RowType == DataControlRowType.Header)
{
totalAmt = 0;
}
else if (e.Row.RowType == DataControlRowType.DataRow)
{
totalAmt += invoice.Amount;
}
else if (e.Row.RowType == DataControlRowType.Footer)
{
var amountTotalLabel = (TextBox) e.Row.FindControl("AmountTotalTextBox");
amountTotalLabel.Text = totalAmt.ToString("0.00");
}
}
TotalAmt is protected instance variable on the page. Not sure if it's what you were looking for based on your comment about "programmatic knowledge." But it works and is fairly straight-forward. The gridview is bound to a List<Invoice> in this case.
Add the footer Template and on the RowDataBound, have a global variable to store the summation sum,
At the e.Row.RowType = DataControlRowType.DataRow type do the summation , and # the e.Row.RowType = DataControlRowType.Footer store the vale in the appropriate cell
for further info look # MSDN LINK
This is how I do it. Very easy. You just sum the row that has your numbers in it and place it in the footer.
((Label)GridView.FooterRow.Cells[1].FindControl("your_label")).Text = ds.Tables[0].Compute("sum(Column_name)", "").ToString();
I think the method I use is pretty basic and doesn't require programatically referring to columns in the Gridview, if that's what you mean. That's one of the nice parts is that once you get the back-end functions written, you can add totals to any Gridview by only editing the .aspx file.
In your GridView, make the column like this:
<asp:TemplateField HeaderText="Hours">
<ItemTemplate><%#DisplayAndAddToTotal(Eval("Hours").ToString(), "Hours")%></ItemTemplate>
<FooterTemplate><%#GetTotal("Hours")%></FooterTemplate>
</asp:TemplateField>
The second parameter to DisplayAndAddToTotal can be any string you want as long as you use the same string in GetTotal. I usually just use the field name again though. Here are the two functions used, DisplayAndAddToTotal and GetTotal. They use a Hashtable to store the totals so that it works with any number of columns you want to add up. And they also work with counting the number of "True"s for a Boolean field.
Protected total As Hashtable = New Hashtable()
Protected Function DisplayAndAddToTotal(itemStr As String, type As String) As Double
Dim item As Double
If itemStr = "True" Then
item = 1
ElseIf Not Double.TryParse(itemStr, item) Then
item = 0
End If
If total.ContainsKey(type) Then
total(type) = Double.Parse(total(type).ToString()) + item
Else
total(type) = item
End If
Return item
End Function
Protected Function GetTotal(type As String) As Double
Try
Dim result As Double = Double.Parse(total(type).ToString())
Return result
Catch
Return 0
End Try
End Function
I know the question is a little choppy and perhaps misleading,but I have a gridview with dropdownlists on the rows. I created an AddHandler and a Delegate for the SelectedIndexChanged and it gets to the sub. Here is the code for that:
AddHandler ddlmgr.SelectedIndexChanged, AddressOf ddlmgr_SelectedIndexChanged
Public Delegate Sub DropDownList_SelectedIndexChanged(ByVal sender As Object, ByVal e As DropDownList_SelectedIndexChanged)
Protected Sub ddlmgr_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
End Sub
How can i get the row's Id if GridView_RowCommand is not called?
You will need to do a bit of the legwork as I cant provide 100% specifics without writing out the code and testing it on my own here, which I am unable to do at present, but the code should go along these lines.
within the ddlmgr_SelectedIndexChaged,
cast your sender to a DropDownList
access the part property of the dropdownlist.
Check it is is a GridItem (or repeateritem or whichever, you get the idea)
If so, get the items itemindex. If not access its parent property.
Continue until you find your Row object.
Hopefully this helps. If not, perhaps someone with a bit more liberal access can chime in
DropDownList ddl = (DropDownList)sender;
Control p = ddl.Parent;
//you are going to loop because the immediate
//parent may not be the repeater item but instead a
//container control of some kind (say a template)
while (p.GetType() != typeof(RepeaterItem))
{
p = p.Parent;
if (p == null) return; //we have reached the top of the control tree
}
RepeaterItem ri = (RepeaterItem)p;
int index = ri.ItemIndex
return index;
Great work
Works absolutely fine for me
DropDownList ddl = (DropDownList)sender;
Control p = ddl.Parent;
//you are going to loop because the immediate
//parent may not be the repeater item but instead a
//container control of some kind (say a template)
while (p.GetType() != typeof(RepeaterItem))
{
p = p.Parent;
if (p == null)
return; //we have reached the top of the control tree
}
RepeaterItem ri = (RepeaterItem)p;
int index = ri.ItemIndexreturn index;
DropDownList ddltxt = (DropDownList)sender;
string temp2 = ddltxt.SelectedItem.Text;
string temp3 = ddltxt.SelectedItem.Value;
string temp = ddltxt.ID.ToString();
int strlength = temp.Length;
string strLastchar = temp.Substring(strlength - 1, 1);
int intlastchar = int.Parse(strLastchar.ToString());
string commonpart = temp.Substring(0, strlength - 1);
if (intlastchar == 1)
{
string targetdropdownid = commonpart + "2";
DropDownList targetlist = (DropDownList)TableRow11.FindControl(targetdropdownid);
using (conn = new SqlConnection(ConnectionString))