My gridview has 2 columns - DropDownList & TextBox. The DDL is databound by a datatable. The SelectedIndex Change of DDL will populate its Textbox and also add a new row. All of this works fine, but the selected values of DDLs of previous rows, reset to 0 index, when a new row is added.The textbox values remain intact though. How can I retain the DDL selected values when adding new rows.
For eg. if I select 'abc' from dropdown of row 1, it populates its text field and also adds a new row. But with the postback happening, abc does not remain selected in row 1 ddl:
LOGIN PHONE
1 123456789
2
ASPX:
<asp:GridView ID="gvCommissions" runat="server"
OnRowDataBound="gvCommissions_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="LOGIN" ItemStyle-Width="29%">
<ItemTemplate>
<asp:DropDownList ID="ddlLogin" runat="server" Width="98%"
DataTextField="login" DataValueField="id"
OnSelectedIndexChanged="ddlLogin_SelectedIndexChanged" AutoPostBack="true" >
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="PHONE" ItemStyle-Width="12%">
<ItemTemplate>
<asp:TextBox ID="txtPhone" runat="server" Width="98%"
Text='<%# Eval("phone")%>' Enabled="false"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
CODE BEHIND:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
//Get values from DB, store to a datatable and then to a viewstate
GetAgentDetails();
//Adds an empty row to grid
SetInitialRow();
}
}
private void AddNewRow()
{
//Create a datatable
dtCurrentData = new DataTable();
dtCurrentData.Columns.Add("phone");
//Store values of each row to a new datarow. Add all rows to datatable
foreach (GridViewRow gvRow in gvCommissions.Rows)
{
DataRow drcurrentrow = dtCurrentData.NewRow();
drcurrentrow["phone"] = ((TextBox)gvRow.FindControl("txtphone")).Text;
dtCurrentData.Rows.Add(drcurrentrow);
}
//create an empty datarow and also add it to the new datatable.
DataRow dr = dtCurrentData.NewRow();
dr["phone"] = "";
dtCurrentData.Rows.Add(dr);
//Bind the new datatable to the grid
gvCommissions.DataSource = dtCurrentData;
gvCommissions.DataBind();
}
protected void gvCommissions_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList ddl = (DropDownList)e.Row.FindControl("ddlLogin");
dtAgents = (DataTable)ViewState["AgentsTable"];
ddl.DataSource = dtAgents;
ddl.DataBind();
ddl.Items.Insert(0, "");
}
}
When you databind in AddNewRow, the original rows are lost. You must store the dropdown selected index, together with your textbox phone value in dtCurrentData. You can then set the index of the dropdowns in your RowDataBound event, using the values your saved in dtCurrentData.
private void AddNewRow()
{
//Create a datatable
dtCurrentData = new DataTable();
dtCurrentData.Columns.Add("phone");
//new column for dropdown index
dtCurrentData.Columns.Add("ddlIndex");
//Store values of each row to a new datarow. Add all rows to datatable
foreach (GridViewRow gvRow in gvCommissions.Rows)
{
DataRow drcurrentrow = dtCurrentData.NewRow();
drcurrentrow["phone"] = ((TextBox)gvRow.FindControl("txtphone")).Text;
//get dropdown index
drcurrentrow["ddlIndex"] = ((DropDownList)gvRow.FindControl("ddlLogin")).SelectedIndex;
dtCurrentData.Rows.Add(drcurrentrow);
}
//create an empty datarow and also add it to the new datatable.
DataRow dr = dtCurrentData.NewRow();
dr["phone"] = "";
//initial drop down index
dr["ddlIndex"] = 0;
dtCurrentData.Rows.Add(dr);
//save to the viewstate like your AgentsTable
ViewState["CurrentData"] = dtCurrentData;
//Bind the new datatable to the grid
gvCommissions.DataSource = dtCurrentData;
gvCommissions.DataBind();
}
protected void gvCommissions_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList ddl = (DropDownList)e.Row.FindControl("ddlLogin");
dtAgents = (DataTable)ViewState["AgentsTable"];
ddl.DataSource = dtAgents;
ddl.DataBind();
ddl.Items.Insert(0, "");
//get the dropdown index from CurrentData
//use the current gridview's row index, since it matches the datatable
if (ViewState["CurrentData"] != null)
{
DataTable dtCurrentData = (DataTable)ViewState["CurrentData"];
ddl.SelectedIndex = Convert.ToInt32(dtCurrentData.Rows[e.Row.RowIndex]["ddlIndex"]);
}
}
}
RowDataBound gets fired every time (irrespective of whether the page is PostBack page or NOT).
You need to add that if(!IsPostBack) condition around the code where you are performing the databinding for the dropdowns in your RowDataBound event.
Related
My problem is this:
I'm creating a gridview that contains buttons. In these buttons, certain default text is displayed.
At the very bottom of the grid, there is a unique button that will create an additional row onclick.
Now, after I create my initial rows on the first page load, and all of the default button attributes are present, I am then able to select a value from a dropdown list that changes the text of the button in the next cell over.
But when I click to add a new row, that button text is reverted back to the default.
The selected value of the dropdown list does not change however.
I'm referencing this tutorial:
http://snipplr.com/view/72801/adding-dynamic-rows-in-gridview-with-dropdownlists-in-aspnet/
But have adjusted the code to include a dynamic button
private void AddNewRowToGrid()
{
if (ViewState["CurrentTable"] != null)
{
DataTable dtCurrentTable = (DataTable)ViewState["CurrentTable"];
DataRow drCurrentRow = null;
if (dtCurrentTable.Rows.Count > 0)
{
drCurrentRow = dtCurrentTable.NewRow();
drCurrentRow["RowNumber"] = dtCurrentTable.Rows.Count + 1;
//add new row to DataTable
dtCurrentTable.Rows.Add(drCurrentRow);
//Store the current data to ViewState
ViewState["CurrentTable"] = dtCurrentTable;
for (int i = 0; i < dtCurrentTable.Rows.Count - 1; i++)
{
//extract the DropDownList Selected Items
DropDownList ddl1 = (DropDownList)Gridview1.Rows[i].Cells[1].FindControl("DropDownList1");
DropDownList ddl2 = (DropDownList)Gridview1.Rows[i].Cells[2].FindControl("DropDownList2");
// Update the DataRow with the DDL Selected Items
dtCurrentTable.Rows[i]["Column1"] = ddl1.SelectedItem.Text;
dtCurrentTable.Rows[i]["Column2"] = ddl2.SelectedItem.Text;
}
//Rebind the Grid with the current data
Gridview1.DataSource = dtCurrentTable;
Gridview1.DataBind();
}
}
else
{
Response.Write("ViewState is null");
}
//Set Previous Data on Postbacks
SetPreviousData();
}
protected void Change_Button(object sender, EventArgs e)
{
DataTable dtCurrentTable = (DataTable)ViewState["CurrentTable"];
GridViewRow row = (GridViewRow)((DropDownList)sender).NamingContainer;
int index = row.RowIndex;
Button btn = (Button)Gridview1.Rows[index].Cells[3].FindControl("btn");
btn.Text = "HELLO";
ViewState["CurrentTable"] = dtCurrentTable;
}
<asp:TemplateField HeaderText="Header 2">
<ItemTemplate>
<asp:DropDownList ID="DropDownList2" runat="server" AppendDataBoundItems="true" AutoPostBack="true" OnSelectedIndexChanged="Change_Button">
<asp:ListItem Value="-1">Select</asp:ListItem>
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Header 3">
<ItemTemplate>
<asp:Button ID="btn" runat="server" Text="Default">
</asp:Button>
</ItemTemplate>
Can anybody explain how I'm able to maintain the desired text, or any attribute for that matter, on the postback?
This is strictly for my own education. I'm trying to learn more about preserving the page's state when I move between webforms.
i have a gridview in a asp.net webform and i add it a check box column like this (the dataTable first column(0) is empty in sql data source and i add check boxes on the column cells):
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (rowNum != 0)//except first row
{
CheckBox cb = new CheckBox();
cb.Enabled = true;
e.Row.Cells[0].Controls.Add(cb);//row[0]=first clmn-and this event happend for all rows
}
rowNum++;
}
now i have a dynamic check box column! and user should check some of them and click the submit then i need the row number of the checked check boxes.
how can i do this?
i tried this before:
DataTable editTable = new DataTable();
editTable.Rows.Add(GridView1.Rows[0]);
var x = editTable.Rows[0][0];
but the x cannot get the check box true or false! it seems that getting me the original field under the check box content.
regards.
Instead of creating the controls dynamically which in most cases results in a lot of trouble, you could add the CheckBoxes in one or more template columns. The following sample shows how to add a checkbox in a template column and how to retrieve the value afterwards:
<asp:GridView ID="gridView" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="chb" runat="server" />
<asp:HiddenField ID="hiddenId" runat="server"
Value='<%# DataBinder.Eval(Container.DataItem, "Id") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Text" />
</Columns>
</asp:GridView>
In my sample, I've bound some data to the GridView:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
var dt = GetData();
gridView.DataSource = dt;
gridView.DataBind();
}
}
private DataTable GetData()
{
var dt = new DataTable();
dt.Columns.Add("Id", typeof(int));
dt.Columns.Add("Text", typeof(string));
for (int i = 0; i < 10; i++)
dt.Rows.Add(new object[] { i, "Test text " + i.ToString() });
return dt;
}
If you need to set the value, you can do so in the RowDatabound event. The following code shows how to retrieve the value of the Checkbox controls:
protected void btn_Click(object sender, EventArgs e)
{
List<int> checkedIds = new List<int>();
foreach(GridViewRow row in gridView.Rows.OfType<GridViewRow>()
.Where(x => x.RowType == DataControlRowType.DataRow))
{
var hiddenId = (HiddenField)row.Cells[0].FindControl("hiddenId");
var checkBox = (CheckBox) row.Cells[0].FindControl("chb");
if (checkBox.Checked)
checkedIds.Add(int.Parse(hiddenId.Value));
}
}
I have a GridView on my asp.net webform with all the columns and rows created in C# code from behind. Except the first column, every cell in each column is a DropDownList with a DataSource.
Here is my GridView:
<asp:GridView ID="gv_Rota" runat="server" AutoGenerateColumns="false" OnRowDataBound="gv_Rota_RowDataBound">
<HeaderStyle BackColor="#6a3d98" ForeColor="White" Height="20" />
<RowStyle HorizontalAlign="Center" Height="20px" Width="100px" />
<AlternatingRowStyle Height="20px" />
</asp:GridView>
And the c# creation of the columns and cells:
private void BindGrid(int Amount)
{
gv_Rota.DataSource = null;
gv_Rota.Columns.Clear();
BoundField bfield = new BoundField();
bfield.HeaderText = "Days";
bfield.DataField = "Days";
gv_Rota.Columns.Add(bfield);
for (int i = 0; i < Amount; i++)
{
int week = i + 1;
string sWeek = "Week " + week.ToString();
TemplateField tfield = new TemplateField();
tfield.HeaderText = sWeek;
gv_Rota.Columns.Add(tfield);
}
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("Days", typeof(string)));
dt.Rows.Add("M");
dt.Rows.Add("T");
dt.Rows.Add("W");
dt.Rows.Add("T");
dt.Rows.Add("F");
dt.Rows.Add("S");
dt.Rows.Add("S");
gv_Rota.DataSource = dt;
gv_Rota.DataBind();
}
And then on the RowDataBound trigger of my GridView, I add the DropDownList control to every cell:
protected void gv_Rota_RowDataBound(object sender, GridViewRowEventArgs e)
{
for (int i = 1; i <= ColumnCount; i++)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
ddlShift = new DropDownList();
ddlShift.ID = "ddlShift";
ddlShift.DataSource = DCListOfShifts;
ddlShift.DataValueField = "SHIFT_ID";
ddlShift.DataTextField = "SHIFT_NAME";
ddlShift.DataBind();
ddlShift.Items.Insert(0, new ListItem("Shift..."));
ddlShift.CssClass = "ddl_rotamanager";
e.Row.Cells[i].Controls.Add(ddlShift);
}
}
}
What is displayed for example on my page:
So my question and problem is that I now want to save each column (except the first) to a database, as a "scheduled week", and have no idea how to get the values of selected items in all or any of the DropDownLists to then pass that back to the database. Baring in mind, this is NOT done on selectedindexchanged. I will select items from all the DropDownLists and then press a button to submit the values. Please could someone give me some highlight on how this could be done? Thanks.
EDIT 1: Response explains how I could get every value of a DropDownList in a row or by individual cell. However, now I need to know more specifically how I can get values of specific cells in the columns rather than the rows. Is it possible to get further highlight on this?
Use Gridview.Rows property
protected void MyButton_Click(object sender, EventArgs e)
{
foreach(GridViewRow row in gv_Rota.Rows)
{
//find this control in this row
DropDownList dd = row.FindControl("MyDropdown") as DropDownList;
//OR
//find this control in a specific cell
DropDownList day = row.Cells[0].FindControl("MyDropdown") as DropDownList;
DropDownList Week1 = row.Cells[1].FindControl("ddShift") as DropDownList;
//this is just a pseudo-code to determine which dropdown was selected per row.
//You can improve on this
if(dd1.SelectedValue != string.Empty)
thisDay.SelectedWeek = dd1.SelectedValue;
else if(dd2.SelectedValue != string.Empty)
thisDay.SelectedWeek = dd2.SelectedValue;
....
}
}
I need to set number of row in data grid view (like identity in sql) in winforms. i am dynamically adding columns and rows in grid view. any idea.
To display text in the row header you can use the Row.HeaderCell.Value as shown below:
void dataGridView1_DataBindingComplete(object sender,
DataGridViewBindingCompleteEventArgs e)
{
DataGridView gridView = sender as DataGridView;
if (null != gridView)
{
foreach (DataGridViewRow r in gridView.Rows)
{
gridView.Rows[r.Index].HeaderCell.Value =
(r.Index + 1).ToString();
}
}
}
This only displays the row number of the new row when the user begins typing in it. Not sure if there is a simple way of always showing the row number on the new row.
Another best way for asp.net application.Here is a link http://www.devcurry.com/2010/01/add-row-number-to-gridview.html
Just add the following tags to your section of your GridView
<Columns>
<asp:TemplateField HeaderText="RowNumber">
<ItemTemplate>
<%# Container.DataItemIndex + 1 %>
</ItemTemplate>
</asp:TemplateField>
...
</Columns>
Method 1:
//You can also use below code
this.DataGridView1.Rows[e.RowIndex].Cell[0].value =e.RowIndex +1;
//get total number of rows
this.DataGridView1.Rows.Count;
Method 2:
for (int i = 0; i < SensorGridView.Rows.Count; i++)
{
DataGridViewRowHeaderCell cell = SensorGridView.Rows[i].HeaderCell;
cell.Value = (i + 1).ToString();
SensorGridView.Rows[i].HeaderCell = cell;
}
Method 3:
void GridView_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
{
this.GridView.Rows[e.RowIndex].Cells[0].Value
= (e.RowIndex + 1).ToString();
}
Why not like this way. Build a datatable first and then bind to grid like below
DataTable tbl = new DataTable();
Datacolumn dc = new Datacolumn("ID");
Datacolumn dc1 = new Datacolumn("col1");
Datarow dr = tbl.NewRow();
dr[dc] = "123";
dr[dc1] = "SomeData";
tbl.Rows.Add(dr);
DataGridView.DataSource = tbl;
I have to bind a label and a drop down in a gridview,the DDL contains rundates that is datetime format i have to show all the different dates in the DDL associated with the name.
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataTable dt = new DataTable();
dt = Common.rundate();
DropDownList ddl = e.Row.FindControl("DropDownList1") as DropDownList;
ddl.DataTextField = "RunDate";
ddl.DataValueField = "TempID";
ddl.DataSource = dt;
ddl.DataBind();
}
}
Store Proc::
alter PROC display_rundates
#rundate datetime,#tempid int
AS
SELECT RunDate,TempID
FROM History_Table
ORDER BY Rundate DESC
GO
But i have to show the specific rundates associated with each Name.Any help can be appreciated.
Name rundate
Test datetime(DDL)
Test1 datetime
Try this
ddl.SelectedValue = ((System.Data.DataRowView)(e.Row.DataItem)).Row["TempId"].ToString();
Basically just get "TempId" from the data item during GridView1_RowDataBound and assign that "TempId" to drop down's Selected value.
Something like this
void bindGrid()
{
grid.DataSource = getRunDates();
grid.DataBind();
}
DataTable getRunDates()
{
DataTable dt = new DataTable();
dt.Columns.Add("TempID");
dt.Columns.Add("RunDate");
dt.Rows.Add(new object[] { 1, "20-May-2012" });
dt.Rows.Add(new object[] { 2, "21-May-2012" });
dt.Rows.Add(new object[] { 3, "10-May-2012" });
dt.Rows.Add(new object[] { 4, "20-May-2012" });
return dt;
}
protected void grid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataTable dt = new DataTable();
dt = getRunDates();
DropDownList ddl = e.Row.FindControl("DropDownList1") as DropDownList;
ddl.DataTextField = "RunDate";
ddl.DataValueField = "TempID";
ddl.DataSource = dt;
ddl.DataBind();
ddl.SelectedValue = ((System.Data.DataRowView)(e.Row.DataItem)).Row["TempId"].ToString();
}
}
Design
<asp:GridView runat="server" ID="grid" OnRowDataBound="grid_RowDataBound" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField HeaderText="RunDate">
<ItemTemplate>
<asp:DropDownList runat="server" ID="DropDownList1" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="TempID" DataField="TempID" />
</Columns>
</asp:GridView>
When you bind the gridview you must also bind the primary key to some template field control,if you have not written it then add hidden field and bind to it as follow
<ItemTemplate>
<asp:HiddenField runat="server" ID="hiddenfield1" Value='<%# Eval("TempID") %>' />
<asp:DropDownList runat="server" ID="ddl" />
</ItemTemplate>
In RowDataBound Event you can findout the PrimaryKey and then use it to set the Dropdown Selected Value as follow...
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataTable dt = new DataTable();
dt = Common.rundate();
DropDownList ddl = e.Row.FindControl("DropDownList1") as DropDownList;
ddl.DataTextField = "RunDate";
ddl.DataValueField = "TempID";
ddl.DataSource = dt;
ddl.DataBind();
HiddenField hdn=(HiddenField)row.Cells[cellindex].FindControl("hiddenField1");
ddl.SelectedValue=hdn.Value;
}
}
I am still not convinced by my solution, but I think this is the way I would go about it...
When loading the data in the first time I would fill a dictionary with the run dates for each name:
private Dictionary<string, List<DateTime>> runDates = new Dictionary<string, List<DateTime>>();
private void LoadData()
{
DataTable table = new DataTable();
table.Columns.Add("TempName", typeof(string));
using (var connection = new SqlConnection("YourConnectionString"))
using (var command = new SqlCommand("SELECT DISTINCT TempName, RunDate FROM History_Table;", connection))
{
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
string tempName = reader.GetString(0);
if (!runDates.ContainsKey(tempName))
{
DataRow row = table.NewRow();
row[0] = tempName;
table.Rows.Add(row);
runDates.Add(tempName, new List<DateTime>());
}
runDates[tempName].Add(reader.GetDateTime(1));
}
}
GridView1.DataSource = table;
GridView1.DataBind();
}
}
When reading each row it checks if the name already exists, if it does not then it adds it to the table that will be used to bind the GridView and to the dictionary. Then in the binding event use the name label to find the list of dates from the dictionary:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//Find the label with the temp name and assign it
string tempName = (e.Row.FindControl("Label1") as Label).Value;
DropDownList ddl = e.Row.FindControl("DropDownList1") as DropDownList;
ddl.DataTextField = "RunDate";
ddl.DataValueField = "TempID";
ddl.DataSource = runDates[tempName];
ddl.DataBind();
}
}
I toyed with various other ideas, one was returning the date list as an xml field with a unique list of names (much like in your previous question), storing this in a hidden field and deserialising on the row databound event, another solution was to generate 2 tables in the data set and define relationships, but this is very similar in principle to the method I have proposed, and I think I prefer this one...