Append GridView-Columns after DataTable was databound - c#

I have a DataTable which I have created in code file and I later bind it to a GridView which i have created by using the drag and drop feature of Visual studio.
However I have added some columns in the GridView which are not supported(correct me if I am wrong) in a DataTable, e.g Hyperlink-Column or CheckBox-Column.
I would like to build the hyperlink column and the checkbox id's with a value derived from a value generated in the DataTable from a particular column. I know I can use DataNavigateUrlfields to build dynamic links but how do I do this with a DataTable that is to be bound later?
I also need the columns in the GridView to appear after the columns in the DataTable.
Any help in the above will be highly appreciated. Any alternatives are also appreciated.

Declaratively added controls will be created first and then the databound/manually created(documented in the Page's Lifecycle, s‌​earch for "controls created declaratively"). Since you want the declarative columns last, you need a hack:
You could use RowDataBound to change the order, so that the AutoGenerated columns are followed by your other columns like Hyperlink or CheckBox columns:
protected void gridOffers_RowDataBound(object sender, GridViewRowEventArgs e)
{
TableCell cell = e.Row.Cells[0];
e.Row.Cells.RemoveAt(0);
//Move first to the end
e.Row.Cells.Add(cell);
cell = e.Row.Cells[0];
e.Row.Cells.RemoveAt(0);
//Move second to the end
e.Row.Cells.Add(cell);
}
However I have added some columns in the GridView which are not
supported(correct me if I am wrong) in a DataTable, e.g
Hyperlink-Column or CheckBox-Column.
They don't need to be supported in the DataTable but in the GridView. The table contains your data and the grid contains the view.

You can try with this code - based on RowDataBound
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:HyperLink ID="HyperLink1" runat="server" Text=""></asp:HyperLink>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
You can adjust you datbound with your event RowDataBound, i added HyperLink control, in order to customize your link as you want.
void GridView_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
var hyperLink = (HyperLink)e.Item.FindControl("HyperLink1");
hyperLink.NavigateUrl ="....";
var checkBox = (CheckBox)e.Item.FindControl("CheckBox1");
checkBox.Checked =....
}
}

Well there is an easy way to append a column if you are using datatable
DataTable yourDataTable = new DataTable();
Load yourDataTable by DataReader or DataAdapter
DataColumn newColumn = yourDataTable.Columns.Add("Total", typeof(Int32));
After that you can bind this datatable into your Gridview.
msdn

Related

GridView Get the row number containing a value

I have a simple code that displays the results with a simple thank you
I just want to fetch the row number that contains a specific value, knowing that the value is unique
For example, the owner id is 3, who got 939119, falls in row number 7
enter image description here
GridView1.DataSource = dt;
dt.DefaultView.Sort = "CRPoints DESC";
GridView1.DataSource = dt.DefaultView;
GridView1.DataBind();
string idcc = GridView1.DataKeys[e.RowIndex].Values[3].ToString();
Label1.Text = idcc;
idcc = 7
Ok, I'm going to be nice today. but, I WILL state that your posted code makes ZERO sense without any context.
I would assume a typical setup is you have a GV. You load it up with data.
Then say on a row click, you want to get information about that row.
So, lets do this with a simple grid.
our GV markup is thus this:
<asp:GridView ID="GVHotels" runat="server" CssClass="table table-hover"
DataKeyNames="ID" AutoGenerateColumns="false" Width="40%" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="First Name" HeaderStyle-Width="100" />
<asp:BoundField DataField="LastName" HeaderText="Last Name" HeaderStyle-Width="100" />
<asp:BoundField DataField="HotelName" HeaderText="Hotel Name" HeaderStyle-Width="120"/>
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="Description" HeaderText="Province" />
<asp:TemplateField HeaderText="hotel as text box">
<ItemTemplate>
<asp:TextBox ID="txtHotel" runat="server" Text="<%# Eval("HotelName") %>" >
</asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="cmdView" runat="server" Text="Row Click" CssClass="btn"
OnClick="cmdView_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
So, two things you have to "learn" or remember:
to get a databound field from the GV, you use .Cells[] collection (starting at 0 for the first column.
to get a "control" you dropped into the GV, you have to use FindControl.
And to drop/have/use/enjoy a plain jane button or drop down, or ANY standard asp.net control in the GV, you have to "wrap" it as the above markup shows (inside of a "TemplateField", and then inside of "ItemTemplate".
So, often you just use "BoundField", but often you can (and will want to) use a standard control in the grid row.
A great example in above is the placing of a plane jane button click in the row (as per above rules).
So, we have this code to load the GV:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadGrid();
}
void LoadGrid()
{
string strSQL = "SELECT * FROM tblhotelsA ORDER BY HotelName";
GVHotels.DataSource = MyRst(strSQL);
GVHotels.DataBind();
}
And now we have/see this:
So, now our button click (to get the one row we click on).
this:
protected void cmdView_Click(object sender, EventArgs e)
{
Button cmdMyRowBtn = (Button)sender;
GridViewRow MyRow = (GridViewRow)cmdMyRowBtn.NamingContainer;
int PKID = (int)GVHotels.DataKeys[MyRow.RowIndex]["ID"];
Debug.Print($"Row index click = {MyRow.RowIndex.ToString()}");
Debug.Print($"Data base PK id = {PKID.ToString()}");
// get a "databound" field - use cells colleciton
Debug.Print($"Hotel name from cells field = {MyRow.Cells[2].Text}");
// get a tempatled column (those standard asp.net controls in the gv
TextBox txtHotel = (TextBox)MyRow.FindControl("txtHotel");
Debug.Print($"Hotel name from text box in gv = {txtHotel.Text}");
}
So, above, when you click, you can then do whatever you want. You can get values, take values and fill out some text boxes - do whatever.
The output from above click is this:
output:
Row index click = 1
Data base PK id = 5
Hotel name from cells field = Inns of Banff
Hotel name from text box in gv = Inns of Banff
So, from above, you should be able to do quite much anything you want.
And of course like any developer, I get VERY tired VERY fast having to type connection string and code to get a data table from sql. So I have this "handy" helper bit of code I used above.
DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
cmdSQL.Connection.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
(so adjust above to use your connection string)
So above should give you the "building" block you need.
So:
To get columns from a given GV row, use .cells[] colleciton.
To get "controls" you may well use in the GV, use find control.
to get row click, see the above button code.
With these 3 things, this should allow you to do just about anything you ever want to do with a GV.
Edit: Get/find a rowindex on a column value - in this case ID
Ok, so really, we want to search/find and obtain the row index from the GV for a given value in the GV - in this case, for a given "ID" value, we want the row index.
AGAIN, context matters. Maybe this is a row click in client side JavaScript code, but as the question is written, then we looking to find the row index for a given ID.
ok, this will work:
Function GetRowIndex(sFind As String, sKey As String, GV As GridView) As Integer
For Each gRow As GridViewRow In GV.Rows
If GV.DataKeys(gRow.RowIndex).Item(sKey) = sFind Then
Return gRow.RowIndex
End If
Next
Return -1
End Function
So, there is no built in translation here.
The REAL issue, is when, where, why you want the row index based on say a given datakey. I been doing this for OVER 10 years, and have NEVER needed to do this.
In other words? DO NOT try and use the gridview as a database, or some "thing" that stores data - it is mostly for display, and if you need to search, then provide a grid search ability, and filter the results.
So, you can search values in the Grid, or values (not displayed) in datakeys.
So, this routine would return the row index for a given data key value. HOWEVER, do NOT just SHOVE general values into datakeys - in 99% of cases, datakeys is for the ONE database primary key value, and those values should NOT be exposed to the end user - they NEVER are to see the database key values - especially with web based software (too high of a security risk).
So, this routine would search datakeys:
Function GetRowIndex(sFind As String, sKey As String, GV As GridView) As Integer
For Each gRow As GridViewRow In GV.Rows
If GV.DataKeys(gRow.RowIndex).Item(sKey) = sFind Then
Return gRow.RowIndex
End If
Next
Return -1
End Function
However, if the data is in the GV, then search that, and does not "needless" add the values to the datakeys (only have/place values in datakeys that you don't want to display or expose to the end user).
So, in above, I can do this:
Dim sFindID As String
sFindID = "5"
Debug.Print($"Row index of given id {sFindID} = {GetRowIndex(sFindID, "ID", GVHotels)}")

how to create Grid view with customized column from different table with asp.net and c#?

now i am very confused with how to create gridview with the following structure and criteria:
note: the gridview will take data from different tables
columns:
1. IDcol the unique value and it will be from tableA(as text)
2. Date it will from also tableA(as text)
3. link1 it will be hyperlink to another page and the parameter for the url will be 'IDcol' column value but the text displayed will changed if this record is exists in tableB with the same 'IDcol' the dispalyed will be "view/edit" if not exists it will be "Add New"
database structure:
tableA:
IDcol as (primary key),
Date
tableB:
ID,
IDcol as (foreign key from tableA).
other fields
so i need populate the gridview using loop because i have to check for each row and use some conditions
sorry if my way of description is not clear but i am really confused
My code for deleting part:
<asp:LinkButton ID="DeleteLink" runat="server" Text="Delete" CommandName="Delete"></asp:LinkButton>
</ItemTemplate>
<ItemStyle Width="100px" />
</asp:TemplateField>
DeleteCommand="DELETE VisitsInfo WHERE ID=#VID">
<DeleteParameters>
<asp:Parameter Name="VID" Type="Int64" />
</DeleteParameters>
in code behind :
protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
int VID = int.Parse(GridView1.DataKeys[0].Value.ToString());
SqlDataSourceVisits.DeleteParameters[0].DefaultValue = VID.ToString();
}
when i click on delete link to delete row it works but when refresh the page its delete another row without click the delete link so why that happened??
No matter how many tables you are using to display data in a Gridview, the best and more flexible approach is to use OnRowDataBound.
//do some database queries to return the appropriate value
DataTable dt = new DataTable();
private void Bind()
{
//set up the dt with all the required data from single or multiple tables
}
//Then in the page Load method, call the above Bind method
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Bind();
}
}
//then do something like the following
int idx = 0;
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
//do some database queries to return the appropriate value, then do something like the following
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Cells[0].Text = dt.Rows[idx][0];
e.Row.Cells[1].Text = dt.Rows[idx][1];
//or maybe
((TextBox)e.Row.Cells[0].FindControl("textBox1")).Text = dt.Rows[idx][0];
((Label)e.Row.Cells[1].FindControl("label2")).Text = dt.Rows[idx][1];
((CheckBox)e.Row.Cells[1].FindControl("chkbx1")).Selected = (bool)dt.Rows[idx][2];
idx++;
}
}
And as Pranay said, you may wish to use Linq and join to get the required data from all tables, though, you can still get them in any other way you feel comfortable with
Create a dataview from the two tables and bind the grid to it. While rendering the GridView, in row events ie. rowbound, you can put your conditions.
If I am getting it right, you want to select some column (like A, B, C) from multiple tables and then show them in gridview. If it is, it can be done in various ways.
1. Create a custom DataSet with your required datacolumns in it and fill it using the select query. Then bind the dataset into gridview.
2. Create a DataTable with your required datacolumns in it and fill it using the select query. Then bind the table into gridview.
3. Add your required columns directly into gridview then add data items in it using loop.
Note: In any cases, UNCHECK the "AutoGenerateColumn" option of the gridview for smooth operation.

changing order of boundfield in gridview

i am trying to develop one application, the data displayed in Gridview. gridview contains many boundfield colums . I recently add a column after the end of last boundfield column of gridview (Imported boundfield column). so i have less chance to move the last boundfield to desired location in mark up. if i move the column to desired place, then i've to modify entire coding while row _databounding. so is there any way we can re order the columns without changing in mark up ?? ..
<asp:BoundField DataField="someData" HeaderText="SomeData"> </asp:BoundField>
<asp:CommandField UpdateText="Update" EditText="Edit" CancelText="|Cancel" ShowEditButton="true" ControlStyle-CssClass="LinkNormal" />
<asp:BoundField DataField="someData2" HeaderText="Imported"> </asp:BoundField>
out put will be like this (EDit/Delete/Imported are boundfield columns )
SomeData | Update| Imported
what i need now gridview shoud display like this
Imported | SomeData | Update
I would suggest moving away from using column indexes, and start using data keys to reference column values in the code-behind. That way, you can change the markup and move columns around without effecting the code-behind.
<asp:GridView ID="GridView1" runat="server" DataKeyNames="Col1, Col2, Col3" ... >
Using data keys, you can get column values like this in the RowDataBound event:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
string col1 = GridView1.DataKeys[e.Row.RowIndex]["Col1"].ToString();
}
It seems, that GridView hasn't such functionailty. Instead of, you can try to obtain indexes of columns in code behind by for example column's header text, below is such function that does the job:
int getColumnIndexByHeaderText(GridView gridView, string headerText)
{
for (int i = 0; i < gridView.Columns.Count; ++i)
{
if (gridView.Columns[i].HeaderText == headerText)
return i;
}
return -1;
}
And use it instead of hardcoded column indexes.

ASP.NET Add column to Gridview

I have a gridview that is displaying data from a database using LINQ to SQL.
AssetDataContext db = new AssetDataContext();
equipmentGrid.DataSource = db.equipments.OrderBy(n => n.EQCN);
I need to add a column at the end of the girdview that will have links to edit/delete/view the row. I need the link to be "http://localhost/edit.aspx?ID=" + idOfRowItem.
Try adding a TemplateField to your GridView like so:
<Columns>
<asp:TemplateField>
<ItemTemplate>
Edit
</ItemTemplate>
</asp:TemplateField>
</Columns>
Within the item template you can place any links you like and bind any data you wish to them from your DataSource. In the example above I have just pulled the value from a column named id.
As things stand this would work fine, however the column above would be aligned left most in the GridView with all the auto generated columns to its right.
To fix this you can add a handler for the RowCreated event and move the column to the right of the auto generated columns like so:
gridView1.RowCreated += new GridViewRowEventHandler(gridView1_RowCreated);
...
void gridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
GridViewRow row = e.Row;
TableCell actionsCell = row.Cells[0];
row.Cells.Remove(actionsCell);
row.Cells.Add(actionsCell);
}
Hope this helps.

Dataset datatable formatting rows

Hi i have a dataset which contains a table retrieved from sql. It has 'product' column and 'price' column. I got the dataset and binded to grid. Now i want to make the grid's price column to be formatted to 2 decimal places(validation). Any idea please.
I should not change the select query since its an SP which gives me the dataset.
if you neither want to use Bound-Field nor change select query than as much i know you have two options left to accomplish this. First is, do value change in your dataset before binding to grid using any loop and the second option is alter values in grid on RowDataBound Event...
By altering value in Dataset:
foreach(dataRow[] dr in dataset.tables[your table index])
{
// max. two decimal places
string val = String.Format("{0:0.##}",Convert.ToDecimal(dr[column index]));
dr[column index] = val;
}
By altering value in Grid:
protected void mygrid_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
mygrid.cell[cell index].Text = String.Format("{0:0.##}",Convert.ToDecimal(dataset.tables[table index][column index][Row Index]));
}
}
Now if you want apply validation for data insert and update you can apply RegularExpressionValidator at your textBox ...
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:RegularExpressionValidator ID="RegularExpressionValidator1" runat="server" ErrorMessage="RegularExpressionValidator"
ControlToValidate="TextBox1" ValidationExpression="^\d{1,2}([.]\d{1})$"> ValidationGroup="MyVal"</asp:RegularExpressionValidator>
Now you have to apply
ValidationGroup="MyVal"
also on click control on which you'll perform its editing and update..
Try this:
<asp:BoundField DataField="Price" DataFormatString="{0:C2}" HeaderText="Price" />
You need to add the "DataFormatString" property to the bound field as shown above. This formats currency values to two decimal places. Check this article.
DataField refers to the name of the column in the datatable, whereas the HeaderText refers to the text which would be shown as the header of the column in grid.

Categories

Resources