I am currently have a gridview with no row, only header. I have an ASP control textbox with a OnTextChange event. So everytime I input into a number into the textbox, my gridview will generate number of rows based on it. And inside the row, will have a dropdownlist
For instance, in my textbox, I type number 2, 2 rows will be generated in the gridview.
I am currently using ASP.NET
Textbox:
[ 2 ]
GridView:
----------------------------------------------------
| S/N | | |
----------------------------------------------------
| 1 | [dropdownlist] | [dropdownlist] |
|--------------------------------------------------|
| 2 | [dropdownlist] | [dropdownlist] |
--------------------------------------------------
Here is a snippet to get you started. Inside your GridView you can use <TemplateField> to create the layout you want. After that you might want to look into the OnRowDataBound event to fill the DropDownLists.
protected void Button1_Click(object sender, EventArgs e)
{
int rowCount = 0;
//get the number from the textbox and try to convert to int
try
{
rowCount = Convert.ToInt32(TextBox1.Text);
}
catch
{
}
//set the new rowcount as a viewstate so it can be used after a postback
ViewState["rowCount"] = rowCount;
//start the function to fill the grid
fillGrid();
}
private void fillGrid()
{
int rowCount = 0;
//get the current row count from the viewstate
if (ViewState["rowCount"] != null)
{
rowCount = Convert.ToInt32(ViewState["rowCount"]);
}
//create a new DataTable with three columns.
DataTable table = new DataTable();
table.Columns.Add("ID", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Created", typeof(DateTime));
//loop to add the row to the table
for (int i = 0; i < rowCount; i++)
{
table.Rows.Add(0, "Name_" + i.ToString(), DateTime.Now.AddMinutes(i));
}
//bind the table to the grid
GridView1.DataSource = table;
GridView1.DataBind();
}
Related
I have this code:
for(int u = 0; u < 3; u++)
{
TableRow row = new TableRow();
for(int i = 0; i < 3; i++)
{
TableCell cell = new TableCell();
cell.ID = "test"+i;
cell.Text = "Cell" + i + "-" +u;
row.Cells.Add(cell);
}
tabAntraege.Rows.Add(row);
}
So now I have an ASP.NET table like so:
| Cell0-0 | Cell1-0 | Cell2-0 |
| Cell0-1 | Cell1-1 | Cell2-1 |
| Cell0-2 | Cell1-2 | Cell2-2 |
Now I want to change the Text in cell "Cell0-0".
So I wrote this code:
TableRow t1 = tabAntraege.Rows[0];
TableCell t2 = t1.Cells[0];
t2.Text = "new Text"
When I try to use my code I get the following error:
system.argumentoutofrangeexception specified argument was out of the range of valid values
Somebody got an idea?
Here the code from the Button event:
protected void test(object sender, EventArgs e)
{
if(tabAntraege.Rows.Count != 0)
{
TableRow t1= tabAntraege.Rows[0];
TableCell t2 = t1.Cells[0];
t2.Text = "new Text";
}
}
I am assuming from what you've posted that you are declaring the table in the markup, but filling it with TableRow and TableCell instances during the Load event.
You'll have to re-create the rows that you've put in the table every time you post back, as well as any controls you've put in the table cells.
Doing that in the Page_Init handler will allow their content and attributes (such as background color, etc.) to be persisted across postbacks.
List controls (such as the DataGrid, DataList, and GridView) will do this automatically if they're databound, but an ordinary Table will not.
Your code should work, but can you try the following:
tabAntraege.Rows[0].Cells[0].Text = "new Text";
Can you check in your code if the tabAntraege has rows first.
I have bind datagrid with following values.
Id as Int,Price as int, IsActive as bit.
Now I want to sort data based on IsActive when i click on column header of IsActive.
I did the same thing for Id and it working properly but for IsActive it is not working.
Below is my code for IsActive field :
private void dataGridView1_SortCompare(object sender, DataGridViewSortCompareEventArgs e)
{
// Try to sort based on the cells in the current column.
e.SortResult = System.String.Compare(e.CellValue1.ToString(), e.CellValue2.ToString());
// If the cells are equal, sort based on the ID column.
if (e.SortResult == 0 && e.Column.Name != "IsActive ")
{
e.SortResult = System.String.Compare(
dataGridView1.Rows[e.RowIndex1].Cells["IsActive "].Value.ToString(),
dataGridView1.Rows[e.RowIndex2].Cells["IsActive "].Value.ToString());
}
e.Handled = true;
}
I want to know How can i sort Boolean data in datagridView.
According to MSDN -DataGridView.SortCompare Event, The SortCompare will be triggered only for columns that have their "SortMode" property set to "Automatic":
DataGridViewColumn col = this.dataGridView1.Columns["IsActive"];
col.SortMode = DataGridViewColumnSortMode.Automatic;
If I may, I would suggest letting .Net doing the dirty job.
Lets assume you have 3 rows in your grid view:
Id Price IsActive
1 1 1
2 2 1
3 11 1
In the way you have implemented the sorting, if you sort by price, row 3 will precede row 2 (the string "11" comes before "2"...).
Preferably you would have your data in a data table, bind the datatable to the gridview and let .Net do the rest:
/// <summary>
/// Binds the Grid view.
/// </summary>
private void BindGridView()
{
//Creating the columns.
//The gridview will know how to sort Items by the type specified in the second argment
DataTable dt = new DataTable();
dt.Columns.Add("Id",typeof(int));
dt.Columns.Add("Price",typeof(int));
dt.Columns.Add("IsActive",typeof(bool));
//Creating some random data
//Replace this with your actual data...
Random rnd = new Random(1);
for (int i = 0; i < 100; i++)
{
int Id = i+1;
int Price = Id%2 == 0? 500-Id*2:350+Id*3;
bool isActive = (Id%5) !=0;
DataRow row = dt.NewRow();
row["Id"] =Id ;
row["Price"] = rnd.Next(1000) ;
row["IsActive"] = isActive;
dt.Rows.Add(row);
}
this.dataGridView1.DataSource = dt;
//making sure all columns are sortable
foreach (DataGridViewColumn col in this.dataGridView1.Columns)
{
col.SortMode = DataGridViewColumnSortMode.Automatic;
}
}
I am currently working on a custom canvas and in that i have to add a table,So i thought dataGrid would be fine. SO i Want to create a "Table" from "Datagrid" by which user can add a table to the canvas at runtime.
Till now, I have tried to Populate DataGrid With a list and succeded.
How Can I add Columns to a Datagrid at runtime,such that the number of columns and header value Would be taken from the user at runtime using a textbox and based on the value of the textbox the datagrid should add columns and header value.
Actually I want to develop a Table in which user passes the no of columns and the column header and the table should be generated.
Or
"Can you suggest me with a way where i should look in order to to "Draw" a Table using DrawingVisual class"
It is a part of GraphicsTable Class
//Custom Classes "DrawingCanvas & GraphicsTable"
public void CreateDataGrid(GraphicsTable graphicsTable, DrawingCanvas drawingCanvas)
{
dt = new DataGrid();
dt.Name = "Data";
dt.ItemsSource = person();
dt.AllowDrop = true;
dt.AutoGenerateColumns = true;
dt.Height = graphicsTable.Rectangle.Height;
dt.Width = graphicsTable.Rectangle.Width;
drawingCanvas.Children.Add(dt);
Canvas.SetTop(dt, graphicsTable.Rectangle.Top);
Canvas.SetLeft(dt, graphicsTable.Rectangle.Left);
dt.Width = dt.Width;
dt.Height = dt.Height;
dt.Focus();
}
//I have just tried to add dome dummy data to the datagrid.
public List<Person> person()
{
List<Person> peep = new List<Person>();
peep.Add(new Person() {});
return peep;
}
public class Person
{
private string name;
private double salary;
public string Names
{
get { return name; }
set { name = value; }
}
public double Salary
{
get { return salary; }
set { salary = value; }
}
}
You can dynamically build the columns of a DataGrid as follows.
public void buildTable(string[] headers)
{
myGrid.Columns.Clear();
foreach (string header in headers)
{
DataGridTextColumn c = new DataGridTextColumn();
c.Header = header;
myGrid.Columns.Add(c);
}
}
If you are setting ItemsSource, however, the number of rows and columns will automatically adjust to match the value of ItemsSource. For example, the following code produces a DataGrid with 3 rows and 3 columns.
dt = new DataTable();
for (int i = 0; i < 3; i++)
dt.Columns.Add("col" + i.ToString());
for (int i = 0; i < 3; i++)
{
DataRow r = items.NewRow();
r[0] = "a" + i.ToString();
r[1] = "b" + i.ToString();
r[2] = "c" + i.ToString();
dt.Rows.Add(r);
}
myGrid.ItemsSource = dt;
+------+------+------+
| col0 | col1 | col2 |
+------+------+------+
| a0 | b0 | c0 |
+------+------+------+
| a1 | b1 | c1 |
+------+------+------+
| a2 | b2 | c2 |
+------+------+------+
Without knowing your exact requirements, I would not bother with manually drawing a table in code unless you have some special need custom graphics and even in that case I would look into using XAML to restyle the DataGrid or it's elements before attempting to render it myself. That's just my opinion though. Best of luck!
EDIT:
If you want to generate the table columns based on user input, you would just need to put the column generation code in a event handler. In your example you could add an event handler for the Textbox TextChanged event as follows. This event handler will run every time the text changes in the Textbox. You may want to add validation to prevent users from keying in large numbers.
private void numColsTextbox_TextChanged(object sender, TextChangedEventArgs e)
{
int numCols;
if (Int32.TryParse(tb.Text, out numCols))
{
myGrid.Columns.Clear();
for (int i = 1; i <= numCols; i++)
{
DataGridTextColumn c = new DataGridTextColumn();
c.Header = "Column " + i.ToString();
myGrid.Columns.Add(c);
}
}
}
I have added rows into gridview. There are 20 columns in gridview. How can i do a colspan-like feature in gridview which could show me 2-3 rows under 2-3 columns and remaining as a colspan.
Basically i wish to implement colspan in gridview on the rows of the gridview.
hence my present gv is like ;
Col 1 Col 2 Col 3 Col 4 ...... Col 20
Cell1 Cell2 Cell3 Cell 4 ...... Cell 20 (For Rows # 1)
I wish to have something like
Col 1 Col 2 Col 3 Col 4 ...... Col 20
Cell1 Cell2 ...... Cell 20 (For Rows # 1)
Let me know for any query.
Thanks
You need to handle the OnRowCreated event of the GridView as follows:
protected void grid_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Header)
{
e.Row.Cells[2].ColumnSpan = 2;
//now make up for the colspan from cell2
e.Row.Cells.RemoveAt(4);
}
}
Your markup should be something like this:
<asp:GridView runat="server" ID="grid" OnRowCreated="grid_RowCreated" >
On the above example, I populated the grid with this:
DataTable dt = new DataTable();
for (int i = 0; i < 5; i++)
{
dt.Columns.Add("Col " + i);
}
for (int i = 0; i < 10; i++)
{
DataRow r = dt.NewRow();
r.ItemArray=new object[]{"row "+i,"row "+i,"row "+i,"row "+i,"row "+i};
dt.Rows.Add(r);
}
grid.DataSource = dt;
grid.DataBind();
And it produces this:
I just realized that you wanted to have the ROWS (not necessarily the header) to have certain colspan, in which case you can do:
protected void grid_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Cells[2].ColumnSpan = 2;
//now make up for the colspan from cell2
e.Row.Cells.RemoveAt(4);
}
}
And it will produce:
BoundField and TemplateField tags has the property ItemStyle-Width="22%" as you can see you can set it for each column with a percentage to be responsive
I have an ASP.NET GridView which has columns that look like this:
| Foo | Bar | Total1 | Total2 | Total3 |
Is it possible to create a header on two rows that looks like this?
| | Totals |
| Foo | Bar | 1 | 2 | 3 |
The data in each row will remain unchanged as this is just to pretty up the header and decrease the horizontal space that the grid takes up.
The entire GridView is sortable in case that matters. I don't intend for the added "Totals" spanning column to have any sort functionality.
Edit:
Based on one of the articles given below, I created a class which inherits from GridView and adds the second header row in.
namespace CustomControls
{
public class TwoHeadedGridView : GridView
{
protected Table InnerTable
{
get
{
if (this.HasControls())
{
return (Table)this.Controls[0];
}
return null;
}
}
protected override void OnDataBound(EventArgs e)
{
base.OnDataBound(e);
this.CreateSecondHeader();
}
private void CreateSecondHeader()
{
GridViewRow row = new GridViewRow(0, -1, DataControlRowType.Header, DataControlRowState.Normal);
TableCell left = new TableHeaderCell();
left.ColumnSpan = 3;
row.Cells.Add(left);
TableCell totals = new TableHeaderCell();
totals.ColumnSpan = this.Columns.Count - 3;
totals.Text = "Totals";
row.Cells.Add(totals);
this.InnerTable.Rows.AddAt(0, row);
}
}
}
In case you are new to ASP.NET like I am, I should also point out that you need to:
1) Register your class by adding a line like this to your web form:
<%# Register TagPrefix="foo" NameSpace="CustomControls" Assembly="__code"%>
2) Change asp:GridView in your previous markup to foo:TwoHeadedGridView. Don't forget the closing tag.
Another edit:
You can also do this without creating a custom class.
Simply add an event handler for the DataBound event of your grid like this:
protected void gvOrganisms_DataBound(object sender, EventArgs e)
{
GridView grid = sender as GridView;
if (grid != null)
{
GridViewRow row = new GridViewRow(0, -1,
DataControlRowType.Header, DataControlRowState.Normal);
TableCell left = new TableHeaderCell();
left.ColumnSpan = 3;
row.Cells.Add(left);
TableCell totals = new TableHeaderCell();
totals.ColumnSpan = grid.Columns.Count - 3;
totals.Text = "Totals";
row.Cells.Add(totals);
Table t = grid.Controls[0] as Table;
if (t != null)
{
t.Rows.AddAt(0, row);
}
}
}
The advantage of the custom control is that you can see the extra header row on the design view of your web form. The event handler method is a bit simpler, though.
I took the accepted answer approach, but added the header to the existing GridView instead of a custom inherited GridView.
After I bind my GridView, I do the following:
/*Create header row above generated header row*/
//create row
GridViewRow row = new GridViewRow(0, -1, DataControlRowType.Header, DataControlRowState.Normal);
//spanned cell that will span the columns I don't want to give the additional header
TableCell left = new TableHeaderCell();
left.ColumnSpan = 6;
row.Cells.Add(left);
//spanned cell that will span the columns i want to give the additional header
TableCell totals = new TableHeaderCell();
totals.ColumnSpan = myGridView.Columns.Count - 3;
totals.Text = "Additional Header";
row.Cells.Add(totals);
//Add the new row to the gridview as the master header row
//A table is the only Control (index[0]) in a GridView
((Table)myGridView.Controls[0]).Rows.AddAt(0, row);
/*fin*/
This article should point you in the right direction. You can programmatically create the row and add it to the collection at position 0.
Note for those who choose to use RowDataBound Method in VB.NET
If you end up with too many extra header rows popping up, add an If Statement that only proceeds if the gridview's header row is nothing (meaning it is the one currently being bound)
If grid.HeaderRow Is Nothing Then
You will have to create a class which extends gridview then override the CreateRow method.
try this as a starting point
Add t.EnableViewState = false; after you add the row:
Dim t As Table = TryCast(grid.Controls(0), Table)
If t IsNot Nothing Then
t.Rows.AddAt(0, row)
End If
t.EnableViewState = false;
Please refer to https://stackoverflow.com/a/9333714/1060656
i created this solution example
To run in your local system will will need to create 2 files ( one for the control and one aspx) you can either do it one project or 2 projects.
GridViewPlus ==> Control class
GridViewPlusCustomHeaderRows ==> a collection to hold custom header class
CustomHeaderEventArgs ==> Event Args when custom header row is created
aspx file ==> Test program
public class GridViewPlus : GridView
{
public event EventHandler<CustomHeaderEventArgs> CustomHeaderTableCellCreated;
private GridViewPlusCustomHeaderRows _rows;
public GridViewPlus() : base ()
{
_rows = new GridViewPlusCustomHeaderRows();
}
/// <summary>
/// Allow Custom Headers
/// </summary>
public bool ShowCustomHeader { get; set; }
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
[MergableProperty(false)]
public GridViewPlusCustomHeaderRows CustomHeaderRows
{
get {return _rows; }
}
protected virtual void OnCustomHeaderTableCellCreated(CustomHeaderEventArgs e)
{
EventHandler<CustomHeaderEventArgs> handler = CustomHeaderTableCellCreated;
// Event will be null if there are no subscribers
if (handler != null)
{
// Use the () operator to raise the event.
handler(this, e);
}
}
protected override void OnRowCreated(GridViewRowEventArgs e)
{
if (ShowCustomHeader && e.Row.RowType == DataControlRowType.Header) return;
base.OnRowCreated(e);
}
protected override void PrepareControlHierarchy()
{
//Do not show the Gridview header if show custom header is ON
if (ShowCustomHeader) this.ShowHeader = false;
base.PrepareControlHierarchy();
//Safety Check
if (this.Controls.Count == 0)
return;
bool controlStyleCreated = this.ControlStyleCreated;
Table table = (Table)this.Controls[0];
int j = 0;
if (CustomHeaderRows ==null )return ;
foreach (TableRow tr in CustomHeaderRows)
{
OnCustomHeaderTableCellCreated(new CustomHeaderEventArgs(tr,j));
table.Rows.AddAt(j, tr);
tr.ApplyStyle(this.HeaderStyle);
j++;
}
}
}
public class GridViewPlusCustomHeaderRows : System.Collections.CollectionBase
{
public GridViewPlusCustomHeaderRows()
{
}
public void Add(TableRow aGridViewCustomRow)
{
List.Add(aGridViewCustomRow);
}
public void Remove(int index)
{
// Check to see if there is a widget at the supplied index.
if (index > Count - 1 || index < 0)
// If no widget exists, a messagebox is shown and the operation
// is cancelled.
{
throw (new Exception("Index not valid"));
}
else
{
List.RemoveAt(index);
}
}
public TableRow Item(int Index)
{
// The appropriate item is retrieved from the List object and
// explicitly cast to the Widget type, then returned to the
// caller.
return (TableRow)List[Index];
}
}
public class CustomHeaderEventArgs : EventArgs
{
public CustomHeaderEventArgs(TableRow tr ,int RowNumber )
{
tRow = tr;
_rownumber = RowNumber;
}
private TableRow tRow;
private int _rownumber = 0;
public int RowNumber { get { return _rownumber; } }
public TableRow HeaderRow
{
get { return tRow; }
set { tRow = value; }
}
}
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Example1();
GridViewExtension1.CustomHeaderTableCellCreated += new EventHandler<CustomHeaderEventArgs>(GridViewExtension1_CustomHeaderTableCellCreated);
}
void GridViewExtension1_CustomHeaderTableCellCreated(object sender, CustomHeaderEventArgs e)
{
TableRow tc = (TableRow)e.HeaderRow;
tc.BackColor = System.Drawing.Color.AliceBlue;
}
private void Example1()
{
System.Data.DataTable dtSample = new DataTable();
DataColumn dc1 = new DataColumn("Column1",typeof(string));
DataColumn dc2 = new DataColumn("Column2",typeof(string));
DataColumn dc3 = new DataColumn("Column3",typeof(string));
DataColumn dc4 = new DataColumn("Column4",typeof(string));
// DataColumn dc5 = new DataColumn("Column5",typeof(string));
dtSample.Columns.Add(dc1);
dtSample.Columns.Add(dc2);
dtSample.Columns.Add(dc3);
dtSample.Columns.Add(dc4);
// dtSample.Columns.Add(dc5);
dtSample.AcceptChanges();
for (int i = 0; i < 25; i++)
{
DataRow dr = dtSample.NewRow();
for (int j = 0; j < dtSample.Columns.Count; j++)
{
dr[j] = j;
}
dtSample.Rows.Add(dr);
}
dtSample.AcceptChanges();
//GridViewExtension1.ShowHeader = false;
GridViewExtension1.ShowCustomHeader = true;
/*
*=======================================================================
* |Row 1 Cell 1 | Row 1 Col 2 (Span=2) | Row 1 Col 3 |
* | | | |
*=======================================================================
* |Row 2 Cell 1 | | | |
* | | Row 2 Col 2 | Row 2 Col 3 |Row 2 Col 4 |
*=======================================================================
*
*
*
*
* */
// SO we have to make 2 header row as shown above
TableRow TR1 = new TableRow();
TableCell tcR1C1 = new TableCell();
tcR1C1.Text = "Row 1 Cell 1";
tcR1C1.ColumnSpan = 1;
TR1.Cells.Add(tcR1C1);
TableCell tcR1C2 = new TableCell();
tcR1C2.Text = "Row 1 Cell 2";
tcR1C2.ColumnSpan = 2;
TR1.Cells.Add(tcR1C2);
TableCell tcR1C3 = new TableCell();
tcR1C3.Text = "Row 1 Cell 3";
tcR1C3.ColumnSpan = 1;
TR1.Cells.Add(tcR1C3);
GridViewExtension1.CustomHeaderRows.Add(TR1);
TableRow TR2 = new TableRow();
TableCell tcR2C1 = new TableCell();
tcR2C1.Text = "Row 2 Cell 1";
tcR2C1.ColumnSpan = 1;
TR2.Cells.Add(tcR2C1);
TableCell tcR2C2 = new TableCell();
tcR2C2.Text = "Row 2 Cell 2";
tcR2C2.ColumnSpan = 1;
TR2.Cells.Add(tcR2C2);
TableCell tcR2C3 = new TableCell();
tcR2C3.Text = "Row 2 Cell 3";
tcR2C3.ColumnSpan = 1;
TR2.Cells.Add(tcR2C3);
TableCell tcR2C4 = new TableCell();
tcR2C4.Text = "Row 2 Cell 4";
tcR2C4.ColumnSpan = 1;
TR2.Cells.Add(tcR2C4);
GridViewExtension1.CustomHeaderRows.Add(TR2);
GridViewExtension1.DataSource = dtSample;
GridViewExtension1.DataBind();
}
}
I wanted to do a similar task but required clickable buttons inside the header - none of the above worked in that case as the event handlers were not wired up (due to the sequencing of the events). In the end i used the headertemplate tag in the appropriate templatefield of the grid view. The html looks a bit more bloated but the events remain intact with no additional code behind effort. For example
<asp:TemplateField >
<HeaderTemplate>
<div>
<div style="text-align: center;padding-bottom: 5px;">
text
</div>
<div>
<asp:Button ID="Button1" runat="server" Text="Apply to all" ToolTip="Apply to all - Special Bolt On" CssClass="sub_button input_btn_5" OnClick="ApplyButton1_Click" />
</div>
</div>
</HeaderTemplate>
<ItemTemplate>....