I have a gridview event OnRowDataBound event handler like this:
protected void MyGridviewEvent(object sender, GridViewRowEventArgs e)
{
if (e.Row.DataItem == "Duration")
{
}
}
This selects the appropriate column in the row. I'd like to change the format of that cell. This cell contains a TimeSpan and I'd like to format it hh:mm.
How's this done?
Thanks.
GridViewRow.DataItem returns the underlying datasource of this row. I doubt that it is a String like Duration. Normally it would be a DataRowView and you can access the datacolumn via index or name. To format a timespan you could use the .net framework 4 ToString version that takes a String with custom format providers. In earlier frameworks you have to do it manually.
VB.Net example(i hope you get it, the important part is the RowDataBound part)
Private Sub BindGrid()
Dim dt As New DataTable
dt.Columns.Add("ID", GetType(Int32)).AutoIncrement = True
dt.Columns.Add("Duration", GetType(TimeSpan))
dt.PrimaryKey = New DataColumn() {dt.Columns("ID")}
Dim newRow As DataRow = dt.NewRow
newRow("ID") = 1
newRow("Duration") = TimeSpan.FromDays(7)
dt.Rows.Add(newRow)
newRow = dt.NewRow
newRow("ID") = 2
newRow("Duration") = TimeSpan.FromMinutes(777)
dt.Rows.Add(newRow)
Me.GridView1.AutoGenerateColumns = True
Me.GridView1.DataSource = dt
Me.GridView1.DataBind()
End Sub
Private Sub GridRowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
Dim row As DataRowView = DirectCast(e.Row.DataItem, DataRowView)
Dim duration As TimeSpan = DirectCast(row("Duration"), TimeSpan)
e.Row.Cells(1).Text = String.Format("{0:00}:{1:00}", duration.TotalHours, duration.Minutes)
End If
End Sub
Try something like this
protected void MyGridviewEvent(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
TimeSpan ts = TimeSpan.Parse(DataBinder.Eval(e.Row.DataItem, "Duration").ToString());
e.Row.Cells[1].Text = String.Format("{0:t}", ts));
}
}
Where e.Row.Cells[1] is the index of the "Duration" column.
Related
I'm trying to dynamically create a datatable that will allow me to populate single records multiple times when a procedure is executed. I know how to create the datatable with the columns I need but my problem is that every time I execute the sub routine to add a record it re-initializes the datatable and wipes out the previously populated record. How do I create the datatable so that it initializes only once? I've tried initializing during the Page_Load event with a 'Not IsPostback' condition but that doesn't work. Any other ideas?
Partial Public Class ContactLookup
Inherits System.Web.UI.Page
Dim dtContacts As New DataTable
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
dtContacts = New DataTable
dtContacts.Columns.Add("Email", GetType(String))
dtContacts.Columns.Add("AccountNum", GetType(String))
End If
End Sub
Protected Sub btnAddContact_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnAddContact.Click
Dim AcctNum As String = txtLocAcct.Text
Dim Email As String = txtEmail.Text
Dim drContacts As DataRow = dtContacts.NewRow
drContacts("Email") = Email
drContacts("AccountNum") = AcctNum
dtContacts.Rows.Add(drContacts)
End Sub
End Class
If I am correct than you need the table returned by the query as datatable. If its so then you can try this. Change your SqlCommand like this,
var dt =new DataTable(); // a new table to populate dynamically.
var reader = cmd.ExecuterReader(CommandBehaviour.SequentialAccess");
dt.Load(reader);
return dt; // now your dt will be query dependent.
Sorry the answer is in C#. You can convert it to VB at http://converter.telerik.com
Updated Answer
In your case i would suggest create a class instead of datatables and datacolumns. See a sample below:
public class Student
{
public string Name{get;set;}
public int Roll{get;set;}
}
In your code behind
private Student _stud = new Student();
private void FillObjects(){
_stud.Name= txtName.Text;
_stud.Roll=Convert.ToInt32(txtRoll.Text);
}
private void ButtonClick{
FillObjects();
YourClass.SaveMethod(_stud);
}
I want to add to my site a simple table/excel-like feauture that will display some values. So, I added a gridview. I don't use Datasets or database biding at all. All I have is a small form with two entries. When the user clicks a button, I want to add some values to the datagridview control as a new row. How do I add a new record to datagridview control in VB.NET?
I have tried this code:
GridView1.Rows.Add(New String() {Value1, Value2})
but I get an error that:
'Add' is not a member of 'System.Web.UI.WebControls.GridViewRowCollection'
My ASPX:
<asp:GridView ID="GridView1" runat="server" Width="731px">
<Columns>
<asp:BoundField HeaderText="Name" />
<asp:BoundField HeaderText="Grade" />
</Columns>
</asp:GridView>
ok. use a datatable like
protected void Page_Load(object sender,EventArgs e)
{
if(!IsPostback)
{
DataTable myDataTable = new DataTable();
DataColumn myDataColumn;
myDataColumn = new DataColumn();
myDataColumn.DataType = Type.GetType("System.String");
myDataColumn.ColumnName = "Value1";
myDataTable.Columns.Add(myDataColumn);
myDataColumn = new DataColumn();
myDataColumn.DataType = Type.GetType("System.String");
myDataColumn.ColumnName = "Value2";
myDataTable.Columns.Add(myDataColumn);
ViewState["Data"]=myDataTable;
}
}
protected void btnAdd(object sender,EventArgs e)
{
Datatable Dt=(Datatable)ViewState["Data"];
DataRow Dr=Dt.NewRow();
Dr[0]=TextBox1.Text;
Dr[1]=TextBox2.Text;
Dt.Rows.Add(Dr);
ViewState["Data"]=Dt;
}
Hope this will help you.
It is pretty easy. All you have to do is to Bind your grid to any Colleciton, such as List, Array, DataTable. Create your record class
Public Class MyRecord
Private _name As String = ""
Private _grade As Integer = ""
Public Property Name() As String
Get
Return Me._name
End Get
Set(ByVal value As String)
Me._name = Value
End Set
End Property
Public Property Grade() As Integer
Get
Return Me._grade
End Get
Set(ByVal value As Integer)
Me._grade = Value
End Set
End Property
End Class
In your Page_Load Bind your grid to List
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPotback Then
Dim list As New List(Of MyRecord)()
list.Add(New MyRecord() With { _
Key .Name = "dsfsdf", _
Key .Grade = 45 _
})
list.Add(New MyRecord() With { _
Key .Name = "dsfsd234f", _
Key .Grade = 50 _
})
Session("MyList") = list
GridView1.DataSource = list
GridView1.DataBind()
End If
End Sub
Then add some form with textboxes and button and handle button on_click event
Protected Sub btn_Click(sender As Object, e As EventArgs) Handles btn.Click
Dim list As New List(Of MyRecord)
If Session("MyList") Is Not Nothing Then
list = DirectCast(Session("MyList"), List(Of MyRecord))
End If
list.Add(New MyRecord() With { _
Key .Name = txt1.Text, _
Key .Grade = Convert.ToInt32(txt2.Text) _
})
GridView1.DataSource = list
GridView1.DataBind()
End Sub
Sorry if there are any errors, I am a C# developer
Adding the row one by one in the button click..
(i tried but its overwirting the same row)
Here it is in vb for you. Tested it, seems to work fine. Declare dt as shared
Imports System.Data
Partial Class _Default
Inherits System.Web.UI.Page
Shared dt As DataTable
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
dt = New DataTable
dt.Columns.Add("Colum1")
dt.Columns.Add("Colum2")
End If
End Sub
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
dt.Rows.Add(TextBox1.Text, TextBox2.Text)
GridView1.DataSource = dt
GridView1.DataBind()
End Sub
End Class
A gridview should be bound to a datasource. You'll need to add a record to this datasource and then call myGridView.Bind() to bind to it.
Lots of info on MSDN about GridViews:
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.aspx
You can do something like this...
static DataTable dt;
private void Form1_Load(object sender, EventArgs e)
{
dt = new DataTable();
dt.Columns.Add("Colum1");
dt.Columns.Add("Colum2");
}
private void button1_Click(object sender, EventArgs e)
{
dt.Rows.Add(textBox1.Text, textBox2.Text);
dataGridView1.DataSource = dt;
}
I have the following code:
Imports System.Data
Partial Class Students_AddWishes Inherits System.Web.UI.Page
Public dt As New DataTable
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
dt.Columns.Add("ID", System.Type.GetType("System.Int32"))
dt.Columns.Add("univirsity", System.Type.GetType("System.Int32"))
dt.Columns.Add("major", System.Type.GetType("System.Int32"))
End Sub
Protected Sub btnAdd_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAdd.Click
Dim row1 As DataRow = dt.NewRow()
row1("ID") = dt.Rows.Count + 1
row1("univirsity") = ddlUnivs.SelectedValue
row1("major") = ddlMajors.SelectedValue
dt.Rows.Add(row1)
GridView1.DataSource = dt
GridView1.DataBind()
End Sub
End Class
The problem is it shows only one row or record. How to make it shows many records?
Your page load event you are not checking if it is a post back:
If Not IsPostBack Then
'process code if it is not a post back
End If
Everytime you click the btnAdd button your page does a post back to the server.
I just noticed that you probably are not understanding the life time of an object.
You had done this in your code:
Public dt As New DataTable
The problem with that is you have defined this is a class variable and once the page has loaded you have an instance of type dt that may have some columns associated with it. But as soon as you record an event such as a button click that reference is destroyed and a new dt is created.
You will have to make some use of session variables or a database to store the state of dt.
Here is an example in C#:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
DataTable dt = new DataTable();
dt.Columns.Add("ID", System.Type.GetType("System.Int32"));
dt.Columns.Add("univirsity", System.Type.GetType("System.Int32"));
dt.Columns.Add("major", System.Type.GetType("System.Int32"));
Session["MyDataTable"] = dt;
}
}
protected void btnAdd_Click(object sender, EventArgs e)
{
DataTable t = (DataTable)Session["MyDataTable"];
DataRow row1 = t.NewRow();
row1["ID"] = t.Rows.Count + 1;
row1["univirsity"] = 3;
row1["major"] = 31;
t.Rows.Add(row1);
Session["MyDataTable"] = t;
GridView1.DataSource = t;
GridView1.DataBind();
}
And the same code in vb.net:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
If Not Page.IsPostBack Then
Dim dt As New DataTable()
dt.Columns.Add("ID", System.Type.[GetType]("System.Int32"))
dt.Columns.Add("univirsity", System.Type.[GetType]("System.Int32"))
dt.Columns.Add("major", System.Type.[GetType]("System.Int32"))
Session("MyDataTable") = dt
End If
End Sub
Protected Sub btnAdd_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim t As DataTable = DirectCast(Session("MyDataTable"), DataTable)
Dim row1 As DataRow = t.NewRow()
row1("ID") = t.Rows.Count + 1
row1("univirsity") = 3
row1("major") = 31
t.Rows.Add(row1)
Session("MyDataTable") = t
GridView1.DataSource = t
GridView1.DataBind()
End Sub
So now what the code does is instantiate a new datatable object as long as we are on the page (first post back) and adds the columns. Once it has defined the data table we throw it in some session state. When you click the add button you cannot in your previous code just keep using dt because dt scope was lost in your prior code. We do this by assigning the sessioned datatable which was stored prior to a temp datatable. We add the row and reset the session that way the next time we add a row it will display the second row, then third row, and so on...
I recommend a good asp.net book on such as Beginning ASP.net 3.5 in C# 2008. There are a ton of vb.net books on the same subject matter.
You need to save the datatable to Session, because local variables are not preserved. So you need to do:
protected override OnLoad(..) //or OnInit
{
dt = Session["DataTable"] as DataTable;
if (dt == null)
{
dt = new DataTable();
//load columns
}
}
protected override OnUnLoad(..)
{
Session["DataTable"] = dt;
}
Session saves the data table reference across postbacks as the web is stateless.
i'm trying to add a new headerrow to a Gridview. This row should appear below the original headerrow.
As far as I know I have two events to choose from:
1.) Gridview_RowDataBound
2.) Gridview_RowCreated
Option 1 is not an option as the grid is not binding the data on each postback.
Option 2 does not work as expected. I can add the row, but it is added before the HeaderRow because the HeaderRow itself is not added yet in this event...
Please assist, thank you!
Code: (InnerTable property is exposed by custom gridview)
Private Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.Header Then
Dim r As New GridViewRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal)
For Each c As DataControlField In CType(sender, GridView).Columns
Dim nc As New TableCell
nc.Text = c.AccessibleHeaderText
nc.BackColor = Drawing.Color.Cornsilk
r.Cells.Add(nc)
Next
Dim t As Table = GridView1.InnerTable
t.Controls.Add(r)
End If
End Sub
Since this is a custom GridView, why don't you consider overriding the CreateChildControls method?
I.e (sorry, C#):
protected override void CreateChildControls()
{
base.CreateChildControls();
if (HeaderRow != null)
{
GridViewRow header = CreateRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal);
for (int i = 0; i < Columns.Count; i++)
{
TableCell cell = new TableCell();
cell.Text = Columns[i].AccessibleHeaderText;
cell.ForeColor = System.Drawing.Color.Black;
cell.BackColor = System.Drawing.Color.Cornsilk;
header.Cells.Add(cell);
}
Table table = (Table)Controls[0];
table.Rows.AddAt(1, header);
}
}
UPDATE
As was mentioned by Ropstah, the sniplet above does not work with pagination on. I moved the code to a PrepareControlHierarchy and now it works gracefully with pagination, selection, and sorting.
protected override void PrepareControlHierarchy()
{
if (ShowHeader && HeaderRow != null)
{
GridViewRow header = CreateRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal);
for (int i = 0; i < Columns.Count; i++)
{
TableCell cell = new TableCell();
cell.Text = Columns[i].AccessibleHeaderText;
cell.ForeColor = System.Drawing.Color.Black;
cell.BackColor = System.Drawing.Color.Cornsilk;
header.Cells.Add(cell);
}
Table table = (Table)Controls[0];
table.Rows.AddAt(1, header);
}
//it seems that this call works at the beginning just as well
//but I prefer it here, since base does some style manipulation on existing columns
base.PrepareControlHierarchy();
}
Nice work guys, I used your technique for grouping my AJAX enabled gridview, and I searched for a long, long time. Cheers.
protected override void PrepareControlHierarchy()
{
if (GroupColumns)
{
#region Group Column
Table table = (Table)Controls[0];
string lastValue = string.Empty;
foreach (GridViewRow gvr in this.Rows)
{
string currentValue = gvr.Cells[GroupColumnIndex].Text;
if (lastValue.CompareTo(currentValue) != 0)
{
// there's been a change in value in the sorted column
int rowIndex = table.Rows.GetRowIndex(gvr);
// Add a new sort header row
GridViewRow sortRow = new GridViewRow(rowIndex, rowIndex, DataControlRowType.DataRow, DataControlRowState.Normal);
TableCell sortCell = new TableCell();
TableCell blankCell = new TableCell();
sortCell.ColumnSpan = this.Columns.Count - 1;
sortCell.Text = string.Format("{0}", currentValue);
blankCell.CssClass = "group_header_row";
sortCell.CssClass = "group_header_row";
// Add sortCell to sortRow, and sortRow to gridTable
sortRow.Cells.Add(blankCell);
sortRow.Cells.Add(sortCell);
table.Controls.AddAt(rowIndex, sortRow);
// Update lastValue
lastValue = currentValue;
}
}
#endregion
}
HideColumns();
base.PrepareControlHierarchy();
}
Try this when you add the row to the InnerTable:
t.Controls.AddAt(1, r)
Here's a quick basic test I did, which seems to work OK:
Protected Sub gridview_DataBound(ByVal sender As Object, ByVal e As System.EventArgs) Handles gridview.DataBound
Dim g As GridView = CType(sender, GridView)
Dim r As New GridViewRow(0, -1, DataControlRowType.Header, DataControlRowState.Normal)
Dim th As New TableHeaderCell()
th.ColumnSpan = g.Columns.Count
th.Text = "This is my new header"
r.Cells.Add(th)
Dim t As Table = CType(g.Controls(0), Table)
t.Rows.AddAt(1, r)
End Sub