The .NET DataGrid control has an AutoGeneratingColumn Event that fires once for every bound data item right after the data source is changed. This is useful because you could define certain columns in the template, like so:
<Columns>
<asp:HyperLinkField DataNavigateUrlFields="ID" DataNavigateUrlFormatString="ww{0}" DataTextField="ID" DataTextFormatString="{0}" HeaderText="ID" />
</Columns>
and then prevent the same column from being replicated when columns are autogenerated from your data source. In this example, you could prevent the ID column from being autogenerated like this:
Private Sub DG_AutoGeneratingColumn(ByVal sender As Object, ByVal e As DataGridAutoGeneratingColumnEventArgs)
Dim headername As String = e.Column.Header.ToString()
If headername = "ID" Then
e.Cancel = True
End If
End Sub
My question is whether a similar functionality can be achieved with a GridView control.
DETAILS
The data source for the gridview is a DataTable object, which I am binding like so:
GridView1.DataSource = results.Tables("Vitals")
GridView1.DataBind()
The number of columns in my DataTable will vary, which is why it is extremely convenient for me to use AutoGenerateColumns.
To do that you should handle the RowCreated event and write something like the following:
private List<int> hideColumnsIndexes = new List<int>();
protected void Page_Load(object sender, EventArgs e)
{
hideColumnsIndexes.Clear();
}
protected void GridView1_OnRowCreated(object sender, GridViewRowEventArgs e)
{
//Find indexes
if (e.Row.RowType == DataControlRowType.Header)
{
for (int i = 0; i < e.Row.Cells.Count; i++ )
{
if (e.Row.Cells[i].Text == "Id")
{
hideColumnsIndexes.Add(i);
}
//Add more columns to hide
}
}
//Hide cells
foreach (var index in hideColumnsIndexes)
{
e.Row.Cells[index].Visible = false;
}
}
Related
I need to get column header inside the DataControlRowType.Data of rowdatabound event of GridView and here's how I'm doing it:
((DataTable)((GridView)sender).DataSource).Columns[i].ColumnName
Is there another, possibly more concise than shown above? Just wanted to check out here.
if (e.Row.RowType == DataControlRowType.Header) {
LinkButton LnkHeaderText = e.Row.Cells[1].Controls[0] as LinkButton;
LnkHeaderText.Text = "Name";
}
protected void gvLista_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
for (int i = 0; i < gvLista.HeaderRow.Cells.Count; i++)
{
string cabecera = gvLista.HeaderRow.Cells[i].Text;
if (cabecera.Equals("ofertaactiva"))
{
int activo = int.Parse(e.Row.Cells[i].Text);
if (activo != 1)
{
e.Row.BackColor = System.Drawing.Color.SandyBrown;
}
break;
}
}
}
}
Here is a way
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Header)
{
e.Row.Cells[0].Text = "Date";
}
}
But the question is why some one would like to change the header name at run-time.
You can use bound-field with header name as follows (need auto generate column to false)
<Columns>
<asp:BoundField DataField="DateField" HeaderText="Date"
SortExpression="DateField" />
</Columns>
Edit-1
To get the column name change it
var columnName= e.Row.Cells[0].Text ;
At least in VB.NET 2010 this approach is flawed -- for some reason (PRB?) e.Row.Cells(x).Text = "" in the RowDataBound event.
Private Sub gvSymbolList_RowDataBound(sender As Object, e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gvSymbolList.RowDataBound
If e.Row.RowType = DataControlRowType.Header Then
Dim i As Integer
For i = 0 To e.Row.Cells.Count - 1
Select Case e.Row.Cells(i).Text.ToLower
Case "symbol"
COL_SYMBOL = i
Case "description"
COL_DESCRIPTION = i
Case "last"
COL_CLOSE = i
Case "change"
COL_CHANGE = i
End Select
Next
End If
I've a repeater which has an asp gridview as following :
<asp:Repeater ID="rep" runat="server" OnItemDataBound="rep_ItemDataBound">
<ItemTemplate>
<asp:GridView ID="grdVw" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="Link" HeaderText="Link" />
</Columns>
</asp:GridView>
</ItemTemplate>
</asp:Repeater>
then on page load I bind a datatable that contains 20 rows to this repeater:
this is my page load code
protected void Page_Load(object sender, EventArgs e){
//dummy code for testing
table.Columns.Add("Name");
table.Columns.Add("Link");
DataRow row ;
for (int i = 0; i <20; i++)
{
row = table.NewRow();
row[0] = "dsadsd";
row[1] = "text";
table.Rows.Add(row);
}
for (int i = 0; i < 10; i++)
{
ds.Tables.Add(table.Copy());
}
rep.DataSource = ds;
rep.DataBind();
}
Then I handle the repeater's ItemDataBoundevent like this:
protected void rep_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item)
{
GridView grdVw = e.Item.FindControl("grdVw") as GridView;
grdVw.DataSource = table;
grdVw.DataBind();
}
}
Suprisingly the result is 20 gridviews!! I am thinking this is because ItemDataBound fires on each row in the table. So in this handler event I bind the table 20 times, but is this logically sound or am I doing something wrong?!
I could easily have a flag to make sure that the data has been bound to the table only once, but what if I've bound a dataset to the repeater? How can I handle this binding to the grid views ?
Change this line of code:
rep.DataSource = ds;
to this:
rep.DataSource = ds.Tables;
You can bind a repeater with a dataset but you need to be careful how you handle the tables inside that set.
this:
rep.DataSource = table;
rep.DataBind();
Should be:
rep.DataSource = {Some Dataset with more than one table};
rep.DataBind();
Then in your handler:
protected void rep_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item)
{
GridView grdVw = e.Item.FindControl("grdVw") as GridView;
//EDIT: my vb was showing.
grdVw.DataSource = ((DataTable)e.Item.DataItem).Rows;
grdVw.DataBind();
}
}
This is not tested but it should work with a little fiddling. What you need to know is that within the repeater you need to be referencing the dataItem of the listItem in order to get a reference to the table. Also Tables are not iEnumerable so make sure you are binding on the rows object.
I have created:
one master page and one content page called Detail.
On Button click event, displaying data in grid view.
In grid view, columns are autogenerated.
I wanted to show 11 column in grid view, but it is more than page
size.
What to do for this?
I have created sql helper file for database connection code and calling that method, not using sqldatasource for connection.
When I trying to do paging, getting error:
The GridView 'GridView1' fired event PageIndexChanging which wasn't
handled.
You need to declare a method on your code behind that handles the PageIndexChanging event.
Something similar to this:
protected void GridView1_PageIndexChanging (object sender, GridViewPageEventArgs e)
{
GridView1.PageIndex = e.NewPageIndex;
bindGridView(); //bindgridview will get the data source and bind it again
}
private void bindGridView()
{
GridView1.DataSource=getData();
GridView1.DataBind();
}
Providing sample code:
protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView1.PageIndex = e.NewPageIndex;
bindGridView(); //bindgridview will get the data source and bind it again
}
protected void Page_Load(object sender , EventArgs e)
{
if(!IsPostBack)
bindGridView();
}
//this is some sample data
private void bindGridView()
{
DataTable t = new DataTable();
t.Columns.Add("Col1");
t.Columns.Add("Col2");
DataRow r = null;
for (int i = 0; i < 25; i++)
{
r = t.NewRow();
r.ItemArray = new object[] { "Val" + i, " Another " + i };
t.Rows.Add(r);
}
GridView1.DataSource = t;
GridView1.DataBind();
}
And this is the markup:
<asp:GridView OnPageIndexChanging="GridView1_PageIndexChanging" AllowPaging="true" PageSize="10" ID="GridView1" runat="server" AutoGenerateColumns="true">
Produces this:
For Paging you can use OnPageIndexChanging for this....
For Example
you have to use OnPageIndexChanging="gvdetails_PageIndexChanging" in your GridView...
You have to write below code into event in code behind like
protected void gvdetails_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
gvdetails.PageIndex = e.NewPageIndex;
BindData();
}
For more detail you can check the below link here I am using page Index change in my article...
Here I use PageIndexChange
I hope this will helps you....Share it with others...Thanks!
This is the final answer:
Imports System.Collections.Generic ' library
Protected Sub grdEmployees_PageIndexChanging1(ByVal sender As Object, ByVal e As
System.Web.UI.WebControls.GridViewPageEventArgs) Handles grdEmployees.PageIndexChanging
grdEmployees.PageIndex = e.NewPageIndex
LoadEmployeeList() 'FUNCTION FOR DATASET
grdEmployees.DataBind()
End Sub
you simply add this to your code :
protected void GridViewTrsEmail_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridViewTrsEmail.PageIndex = e.NewPageIndex;
GridViewTrsEmail.DataBind();
}
To fix this, I had to take a closer look at my datasource and datakeys. I have a set of records that are returned from SQL Server and what I was doing is binding them to a POCO. This class had several public properties of type Integer. These Integers were my datakeys on the grid. I replaced their type with a string instead to bypass the casting issue.
This is a Master-Detail form. Master is a GridView. And, the Detail is a DetailsView.
The entire thing is achieved programmatically.
As you can see from the code, DetailsView is using the Master-objects's ID to retrieve the Detail items.
I need to make the ID column of the Master-GridView invisible. Coz, it is irrelevent for the user of the page. But it must not harm the page logic.
But the code-line, GridView1.Columns[1].Visible = false; is generating an exception.
Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
How should I solve this problem?
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindData();
}
}
protected void BindData()
{
List<Order> orders = Order.Get();
GridView1.DataSource = orders;
GridView1.DataBind();
// This is giving Error...............!!!
GridView1.Columns[1].Visible = false;
// At first, when the page first loads,
// GridView1.SelectedIndex == -1
// So, this is done to automatically select the 1st item.
if (GridView1.SelectedIndex < 0)
{
GridView1.SelectedIndex = 0;
}
int selRowIndex = GridView1.SelectedIndex;
int selMasterId = Convert.ToInt32(GridView1.Rows[selRowIndex].Cells[1].Text);
Order master = Order.Get(selMasterId);
labItemsCount.Text = master.Items.Count.ToString();
DetailsView1.DataSource = master.Items;
DetailsView1.DataBind();
}
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
BindData();
}
protected void DetailsView1_PageIndexChanging(object sender, DetailsViewPageEventArgs e)
{
DetailsView1.PageIndex = e.NewPageIndex;
BindData();
}
}
Have you considered using the DataKeyNames property of the gridview? This way you can remove the 'id' column from the GridView bu still access the 'id' value in the Page_Load.
DataKeyNames = "id"
Then you can get the value of the id like this.
int selRowIndex = GridView1.SelectedIndex;
int selMasterId = Convert.ToInt32(GridView.DataKeys[selRowIndex].Value);
Order master = Order.Get(selMasterId);
Alternately, you could try changing the visibility of the column in the OnRowBound event of the GridView.
protected void GridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Header ||
e.Row.RowType == DataControlRowType.DataRow ||
e.Row.RowType == DataControlRowType.Footer)
{
e.Row.Cells[1].Visible = false;
}
}
So far I have done this, I am not sure whether this is right or wrong
public partial class _Default : System.Web.UI.Page
{
Label l = new Label();
GridView gv = new GridView();
protected void Page_Load(object sender, EventArgs e)
{
for (int i = 0; i < 5; i++)
{
GridViewRow gvr = new GridViewRow(i, i, DataControlRowType.DataRow, DataControlRowState.Normal);
gvr.Controls.Add(l);
gv. (what to do here)
}
this.Controls.Add(gv);
}
}
please help
gv.Rows.Add(gvr);
If you're starting with an empty GridView, an easier way to dynamically create x rows is to create a dummy list and then set it to the data source:
var list = new List<string>(10); // replace 10 with number of empty rows you want
// for loop to add X items to the list
gv.DataSource = list;
gv.DataBind();
If you are doing this, I'd recommend doing it with a Repeater. It's a lot easier to manage.
The DataGrid fires the RowCreate event when a new row is created.
Collapse
//OnRowCreated="GridView3_RowCreated"
protected void GridView3_RowCreated(object sender, GridViewRowEventArgs e)
{
//When a child checkbox is unchecked then the header checkbox will also be unchecked.
if (e.Row.RowType == DataControlRowType.DataRow && (e.Row.RowState ==
DataControlRowState.Normal || e.Row.RowState == DataControlRowState.Alternate))
{
CheckBox chkBxSelect = (CheckBox)e.Row.Cells[1].FindControl("chkselect");
CheckBox chkBxHeader = (CheckBox)this.GridView3.HeaderRow.FindControl("chkHeader");
chkBxSelect.Attributes["onclick"] = string.Format("javascript:ChildClick(
this,'{0}');", chkBxHeader.ClientID);
}
}