I have a GridView that has a column called Active which shows either a 1 (for active) or a -1 for inactive.
However as this is being implemented into a front end UI I do not want users to be presented with what seems to them as useless integers, however a Active or Not active to be presented in the GridView on Page_Load.
The code would look something like -
protected void Page_Load(object sender, EventArgs e)
{
//code here to modify the column 'Active' in the GridView
//GridView ID="GV1"
if (row.Cells[1].Text == "1")
{
row.Cells[1].Text = "Active";
}
if (row.Cells[1].Text == "-1")
{
row.Cells[1].Text = "Not Active";
}
}
And the column in the GridView is -
<asp:BoundField HeaderText="Active" DataField="Active" SortExpression="Active"></asp:BoundField>
How can I do this as I do not want to edit the database in order for the UI to be more presentable?
Try the OnRowDataBound Gridview event.
Related
I have a .ascx user control on an .aspx page. When the user clicks a button, information is gathered and stored in the database. Then a Gridview is databinded and in the Gridview is a dropdownlist. This dropdownlist's Items are created dynamically based on the users previous input, now in the database. This is all good and the Gridview is displayed with the dropdownlist with the dynamically created Items.
The problem is on the postback for this dropdownlist. I obviously have to recreate the Gridview with the dynamically created Items in the dropdownlist. This does not work. The postback happens and calls the Page_Init and then the Page_InitComplete. This has the databind on the Gridview which calls the SectionGV_OnRowDataBound method. The dropdownlists are recreated. But the SectionDD_OnSelectedIndexChanged method is never hit and then the dropdownlist just reverts back to its original value. I can not change the dropdownlist's selected value.
.ASCX
<asp:GridView ID="MyGV" runat="server" AutoGenerateColumns="False" DataSourceID="MyDS" Width="100%" OnRowDataBound="MyGV_OnRowDataBound">
<Columns>
<asp:TemplateField >
<ItemTemplate>
<asp:DropDownList runat="server" ID="SectionDD" AppendDataBoundItems="True" AutoPostBack="True" OnSelectedIndexChanged="SectionDD_OnSelectedIndexChanged" >
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code Behind of .ASCX
protected void Page_Init(object sender,EventArgs e)
{
this.Page.InitComplete += Page_InitComplete;
}
private void Page_InitComplete(object sender, EventArgs e)
{
MyGV.DataBind();
}
protected void SectionDD_OnSelectedIndexChanged(object sender, EventArgs e)
{
}
protected void MyGV_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
using (EntitiesModel dbContext = new EntitiesModel())
{
// get array[][] array from database
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList sectionDd = (DropDownList)e.Row.FindControl("SectionDD");
sectionDd.Items.Clear();
if (array.Length == 3)
{
if(array[0][2].ToDecimal() > 0) sectionDd.Items.Add(new ListItem(array[0][0], array[0][1]));
if(array[1][2].ToDecimal() > 0) sectionDd.Items.Add(new ListItem(array[1][0], array[1][1]));
if(array[2][2].ToDecimal() > 0) sectionDd.Items.Add(new ListItem(array[2][0], array[2][1]));
}
else if (array.Length == 2)
{
if (array[0][2].ToDecimal() > 0) sectionDd.Items.Add(new ListItem(array[0][0], array[0][1]));
if (array[1][2].ToDecimal() > 0) sectionDd.Items.Add(new ListItem(array[1][0], array[1][1]));
}
else if (array.Length == 1)
{
if (array[0][2].ToDecimal() > 0) sectionDd.Items.Add(new ListItem(array[0][0], array[0][1]));
}
}
sectionDd.DataBind();
}
}
}
}
private void SaveToDB()
{
//save information to database
NOTE
This is one of many ways I have tried to solve this issue. The reason I have saved the information in the database is just a temporary fix. I just want to solve the issue outlined above and then I will add a ViewState solution.
First up, no, you do not have to re-create or load the grid again, or the dropdown list in the post back.
The user can type into the grid - change values, select drop downs. At that point you can loop all the grid rows and get/grab the dropdown values selected.
You CAN of course fire/trigger a event for the dropdown, but it not at all clear if you really need that event here.
If your grid is getting messed up on post-backs?, then it means you not limiting the load up in the FIRST page load - after that, it should not matter.
Say we have this grid markup:
<asp:GridView ID="MyGrid" runat="server" CssClass="table table-hover"
DataKeyNames="ID" AutoGenerateColumns="false" OnRowDataBound="MyGrid_RowDataBound" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="Last Name" />
<asp:BoundField DataField="HotelName" HeaderText="Hotel Name" />
<asp:TemplateField HeaderText="City">
<ItemTemplate>
<asp:DropDownList ID="DropDownList1" runat="server"
DataTextField="City"
DataValueField="City"
>
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Province" HeaderText="Province" />
</Columns>
</asp:GridView>
And of course non templated fields (such as the first few boundField - they appear in the .Cells collection. but for templated columns, you use findcontrol.
However, in EVERY and NEAR ALL web pages, as a general rule, you ONLY load + mess + create the grid ONE time, and you ONLY do this on the first page load - END OF STORY! You don't follow this rule, then you are in a world of hurt big time.
Ok, so lets load up the grid. Since we have a dropdown, then we have to fill that out on item data bound.
So, our code will look like this:
public DataTable rstCity = new DataTable();
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack == false)
{
LoadGrid();
}
}
public void LoadGrid()
{
using (SqlCommand cmdSQL = new SqlCommand("SELECT City from City Order by City",
new SqlConnection(Properties.Settings.Default.TEST4)))
{
// locd city for drop down list
cmdSQL.Connection.Open();
rstCity.Load(cmdSQL.ExecuteReader());
// now load grid
cmdSQL.CommandText = "SELECT * from tblHotels ORDER BY HotelName";
DataTable rst = new DataTable();
rst.Load(cmdSQL.ExecuteReader());
MyGrid.DataSource = rst;
MyGrid.DataBind();
}
}
Note how I did scope the city table to the class level (no reason to load it over and over for each row - and after the first page load, it will go out of scope - we don't care - it will live during the first page load and the data binding.
Ok, now, lets do the item data bind for the grid.
We have this:
protected void MyGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList MyDrop = (DropDownList)e.Row.FindControl("DropDownList1");
MyDrop.DataSource = rstCity;
MyDrop.DataBind();
// get City from current data row source - set the drop to data row City
MyDrop.SelectedValue = ((DataRowView)e.Row.DataItem)["City"].ToString();
}
}
Ok, that's it. (note how the "dataitem" exists ONLY during data binding - a handy tip, since then you have use of the FULL data row - including PK values, and columns that you don't even include in the grid markup. But, once data binding is over, then DataItem can NOT be used - it only EVER exists during the bind process. But this information is VERY valuable, since you have full use of the Actual data SOURCE you used to bind. In above, I needed the City from that Row to set the drop list.
Ok, the output now looks like this:
Ok, at this point since we ONLY bind on first page load. The view state of that grid is 100% automatic handled by asp.net for you at this point in time.
You can drop other buttons on this form - post backs should NOT matter. The BIG lesson here is that gridview does persist (at least it will if we don't re-load it each time on post-back - you should NOT have to re-load).
Ok, next issue:
In most cases, I don't see the need for the dropdown list event in the grid?
So, you can as a general rule select and change any row combo. Once done, then you can get values of each row by looping the data grid rows - including that of dropdown selected.
However, Lets wire up the dropdown list event anyway.
tip of the day:
Since we can't select the dropdown and use the property sheet?
Then in markup do this:
You can in the markup type in OnSelectedIndexChanged=
WHEN you hit the "=" sign, note VERY close how intel-sense pops up a event create option:
So, click on CreateNewEvent - it "seems" like nothing occurs, but in fact if you flip over to code behind, you have a nice event stub created.
So lets put our code in that event - grab the row - show the value just slected.
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
// user changed the combo box
DropDownList MyDrop = (DropDownList)sender;
GridViewRow gRow = (GridViewRow)MyDrop.Parent.Parent;
Response.Write("<h2>Row index is = " + gRow.RowIndex.ToString() + "</h2>");
Response.Write("<h2>Hotel Name is = " + gRow.Cells[2].Text + "</h2>");
Response.Write("<h2>City from Drop selected = " + MyDrop.SelectedValue + "</h2>");
}
Of course we set auto post back = true in the drop markup also - right?
And note how we pick up the "sender", and then use .Parent.Parent to get the grid row that we are operating on. The first parent is some cell or some such.
I actually built recursive function to get that value, but for here we just used .parent.Parent (often with a extra markup, then you need to go op one more .parent).
Anyway, now say I select the last drop down in above, and change it.
I get this output:
In summary:
Only EVER load the grid - first page load - (you check IsPostBack).
You can have all kinds of additional post backs - the grid should survive and just be fine - no need to re-load at all. (GridView has built in viewstate).
Now, after I have fun, change the drop down on many rows?
I can loop the gridview - and any changes to that grid will persist.
In fact, if you make the columns text boxes (in templated fields), then you can tab around and edit almost like Excel, and again the values will persist for you, and they survive post backs. (and then you can send the whole grid of changes back to the database in one update command - I can show how to do this, but this post already has lots of good stuff anyway.
Now, having said the above, having done the above?
Well now that we have this working, then one can go back to building a custom user control - but if done right, it also should behave correctly, and should also survive post-backs.
This is my GridView1. I want the latest record to be highlighted and after user click the authorization no(which user viewed the record in next page), the row will not be highlighted (means after the user view the record, the row is back to normal, no highlight no bold font).
My current progress is,
I have created new bit field in my database named ReadStatus, and defaulted to 0
Next, I need to do the onrowdatabound coding in order to implement this.
first question is, do i need to read the bit column(ReadStatus) as I read all this column?AuthorizationNo, ProductID,Name,Qty,---(ReadStatus)??
should I read ReadStatus in this code?
/ /READING RECORD FROM TABLE TRACK_ITEM
while (reader.Read())
{
MerchantProduct merchantProduct = new MerchantProduct();
merchantProduct.TxID = reader["TxID"].ToString();
merchantProduct.ProductID = reader["ProductID"].ToString();
merchantProduct.Name = reader["ProductName"].ToString();
merchantProduct.Qty = Convert.ToInt32(reader["Qty"]);
listLatestProduct.Add(merchantProduct);
}
return listLatestProduct;
second is, can anyone show me the proper way to code in onrowdatabound?
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
//Tried many code here but none is working
}
Thank you.
First you need to add one more column in ur db for ReadStatus(1/0),
then make is as hiddenfield in your aspx page.
<asp:TemplateField HeaderText="ReadStatus" Visible="false">
<ItemTemplate>
<asp:Label ID="readStatus" runat="server"></asp:Label>
<asp:HiddenField ID="readStatusHiddenField" runat="server" Value='<%#Eval("ReadStatus") %>'/>
</ItemTemplate>
</asp:TemplateField>
In your grid rowdataboun, just paste this code.It works for me
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
// searching through the rows
if (e.Row.RowType == DataControlRowType.DataRow)
{
int reading = Convert.ToInt32(((HiddenField)e.Row.FindControl("readStatusHiddenField")).Value);
if (reading == 0)
{
e.Row.BackColor = Color.LightGray;
e.Row.Font.Bold = true;
}
}
}
I have .NET project on WebForms and GridView in it. GridView is populated with data from my DB. The DB has column named password but on GridView this column is set to Visible="False". When i click command button Edit all boxes are ready to be filled with new data, but column password is invisible.
My question is: when i click edit, how to (or can i) make column with passwords visible and ready for filling text box with new passwords, but also i don't want to show other password of course. Summary can i access somehow properties of this TempleteField/ItemTemplete ?
No need to set the Visible="false" property. Just trick the GridView to hide a column in normal display mode and show the column when in edit mode.
Assuming Password Column is the third column, Handle the RowDataBound event of GridView to hide this Column:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
// Just return in case GridView is rendering in Edit Mode
if (GridView1.EditIndex >= 0)
return;
// In case GridView is rendering in Normal state
// Hide the Columns you don't want to display
if ((e.Row.RowState == DataControlRowState.Normal ||
e.Row.RowState == DataControlRowState.Alternate) &&
( e.Row.RowType == DataControlRowType.DataRow ||
e.Row.RowType == DataControlRowType.Header))
{
// Hide the Password Column
e.Row.Cells[2].Visible = false;
}
}
In case you use TemplateField for your Password Column, you can hide it by using the DataBound event of GridView as:
protected void GridView1_DataBound(object sender, EventArgs e)
{
if (GridView1.EditIndex >= 0)
return;
GridView1.Columns[2].Visible = false;
}
Now when the GridView goes to Edit Mode ( on click of Edit Button etc..) it will display the Password column in Edit Mode.
I have a data grid, and data is coming from database, it has combo boxes in status and I want them to be according to their respective values, for example, there is a column of status, it has a combo box: Open and Close, I want it to be changed with respect to the value it has in database table-column, if it has Close written in database table column, combo box should be selected as Close, if it has Open then it should be selected as Open. Please see the image attached.
Thanks for Help in advance.
Assuming that you're using a template column, you can do this:
<asp:TemplateColumn>
<ItemTemplate>
<asp:DropDownList ID="DropDownList1" runat="server" SelectedValue='<%# Eval("DropDownValueColumn") %>' />
</ItemTemplate>
</asp:TemplateColumn>
If you want to set the SelectedValue in the ItemDataBound event, you can do it like this:
protected void DataGrid1_ItemDataBound(object sender, GridItemEventArgs e)
{
DropDownList ddl = e.Item.FindControl("DropDownList1") as DropDownList;
if (ddl != null)
{
ddl.SelectedValue = DataBinder.Eval(e.Item.DataItem, "DropDownColumnValue").ToString();
}
}
First of all save your data source in viewstate. If datasource is datatable then do like this.
protected void gridview1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList ddlList = (DropDownList)e.Row.FindControl("Name_of_DPList");
int i=e.Row.RowIndex;
DataTable dtTable = (DataTable)ViewState["dtPurchaseOrder"];
string str = dtTable.Rows[i]["Name_Of_column"].ToString();//Name of the column in data source that stores the status.
ddlList.items.FindByText(str).Selected=true;
}
}
Is it possible to have a Checkbox that only shows up when Editing the last row of a GridView?
I have tried something like this in the EditItemTemplate:
<asp:CheckBox ID="chkNextDay" runat="server"
ToolTip="Is it a next-day departure?"
Enabled="true"
Checked='<%# DateTime.Parse(Eval("OutHour","{0:d}")).Date >
DateTime.Parse(Eval("InHour","{0:d}")).Date %>'/>
Then on code-behind I tried hiding it for rows other than the last one like this:
protected void grvOutHour_RowEditing(object sender, GridViewEditEventArgs e)
{
GridView grvOutHour = (GridView)this.grvReport.Rows[grvReport.EditIndex].FindControl("grvOutHour");
TextBox txtBox = (TextBox)grvOutHour.Rows[e.NewEditIndex].FindControl("txtEditOutHour");
CheckBox nextDay = (CheckBox)grvOutHour.Rows[e.NewEditIndex].FindControl("chkNextDay");
if (grvOutHour.Rows.Count-1 != e.NewEditIndex)
nextDay.Visible = false;
}
This ALMOST worked, but the checkbox kept showing for all fields, I think because the RowDataBound is called AFTER RowEditing again so it renders the whole thing again :(
Any suggestions?
Thanks,
EtonB.
Use RowDataBound instead...
protected void grvOutHour_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowState == DataControlRowState.Edit)
{
GridView grid = (GridView)sender;
CheckBox nextDay = (CheckBox)e.Row.FindControl("chkNextDay");
nextDay.Visible = (e.Row.RowIndex == (grid.Rows.Count - 1));
}
}
You will need to handle hiding the checkbox in the RowDataBound event.
You'll need to determine what the last row is, and set the checkboxes visible property to true when that condition is true, obviously.
I guess it's more of a hack than an elegant solution, but I would probably just hide the other checkboxes via JavaScript if the condition is true.