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.
Related
I have a GridView in a ASP.NET web application, in which I have added buttons in each row:
<asp:GridView ID="gridviewdatadosen" runat="server" AutoGenerateColumns="False" CssClass="table table-striped table-bordered table-hover" OnRowDataBound="gridviewdatadosen_RowDataBound" OnSelectedIndexChanged="gridviewdatadosen_SelectedIndexChanged" OnRowCommand="gridviewdatadosen_RowCommand">
<Columns>
<asp:BoundField DataField="NIK" HeaderText="NIK" SortExpression="NIK"></asp:BoundField>
<asp:BoundField DataField="NIDN" HeaderText="NIDN" SortExpression="NIDN"></asp:BoundField>
<asp:BoundField DataField="NAMA" HeaderText="NAMA" SortExpression="NAMA"></asp:BoundField>
<asp:BoundField DataField="Alamat" HeaderText="Alamat" SortExpression="Alamat"></asp:BoundField>
<asp:TemplateField ShowHeader="false">
<ItemTemplate>
<asp:Button ID="btnstatus" runat="server" Text="Aktif" CssClass="btn btn-primary" CommandName="aktifasi" CommandArgument='<%# Eval("NIK") %>'/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
I fill the datagridview on the server side. I filled it with taking the data in the database.
DataTable dt = new DataTable();
DataTable dt1 = new DataTable();
SqlConnection conn = new SqlConnection(#"Data Source=localhost;Initial Catalog=SKRIPSI;User ID=sa;Password=sa");
conn.Open();
string ngisi = "SELECT [nik] as 'NIK' , [nidn] as 'NIDN', [nama] as 'NAMA', [alamat] as 'Alamat' FROM [dosen]";
SqlCommand comm = new SqlCommand(ngisi, conn);
dt.Load(comm.ExecuteReader());
conn.Close();
gridviewdatadosen.DataSource = dt;
gridviewdatadosen.DataBind();
int tmp = dt.Rows.Count;
after I fill the datagridview, I wanted to check the status of dosen whether he is active or not by select id and status of dosen.
conn.Open();
string check = "SELECT nik, status FROM [dosen]";
comm = new SqlCommand(check, conn);
dt1.Load(comm.ExecuteReader());
conn.Close();
I have tried to change the existing text on the button but did not succeed.
for (int i = 0; i < tmp; i++)
{
if (dt1.Rows[i][1].ToString() == "Aktif")//check the dosen aktif or not
{
for (int j = 0; j < tmp; j++)
{
if (dt.Rows[j][0].ToString() == dt1.Rows[i][0].ToString())// check nik where status = 'Aktif'
{
// I want to change the button in each row. if he 'Aktif' then the text in button will change to be 'aktif'
//do not know what to do
}
}
}
}
I want to change the button in each row. if he 'Aktif' then the text in button will change to be 'aktif'. help me to solve this problem. Sorry if my english or my explain is bad. Thank You
You can loop all the rows, find the Button and change the Text based on the values in dt1
foreach (GridViewRow row in GridView1.Rows)
{
//find the button in the row with findcontrol and cast back to a button
Button button = row.FindControl("btnstatus") as Button;
//check dt1 and set button text
button.Text = "Active";
}
Or you can do the same on the GridView databinding with the OnRowDataBound event.
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//find the button in the row with findcontrol and cast back to a button
Button button = e.Row.FindControl("btnstatus") as Button;
//check dt1 and set button text
button.Text = "Active";
}
}
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;
....
}
}
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.
I'm write the code which create new row in gridview when click button. The number of rows are created by value in textbox. Ex: When i enter value 2 in textbox, of course two rows will be added, but when i clicked button again, third rows still added. Please check my code here:
ASPX
<asp:TextBox ID="txtVisitor" runat="server"></asp:TextBox>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:GridView ID="Gridview1" runat="server" ShowFooter="true" AutoGenerateColumns="false">
<Columns>
<asp:BoundField DataField="RowNumber" HeaderText="Row Number" />
<asp:TemplateField HeaderText="Header 1">
<ItemTemplate>
<asp:TextBox ID="txtDate" runat="server"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Header 2">
<ItemTemplate>
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Header 3">
<ItemTemplate>
<asp:TextBox ID="TextBox3" runat="server"></asp:TextBox>
</ItemTemplate>
<FooterStyle HorizontalAlign="Right" />
<FooterTemplate>
<asp:Button ID="ButtonAdd" runat="server" Text="Add New Row" OnClick="ButtonAdd_Click" />
</FooterTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</ContentTemplate>
</asp:UpdatePanel>
Code_Behind
protected void ButtonAdd_Click(object sender, EventArgs e)
{
int visitors = Convert.ToInt32(txtVisitor.Text);
AddNewRowToGrid(visitors);
}
private void SetInitialRow()
{
DataTable dt = new DataTable();
DataRow dr = null;
dt.Columns.Add(new DataColumn("RowNumber", typeof(string)));
dt.Columns.Add(new DataColumn("Column1", typeof(string)));
dt.Columns.Add(new DataColumn("Column2", typeof(string)));
dt.Columns.Add(new DataColumn("Column3", typeof(string)));
dr = dt.NewRow();
dr["RowNumber"] = 1;
dr["Column1"] = string.Empty;
dr["Column2"] = string.Empty;
dr["Column3"] = string.Empty;
dt.Rows.Add(dr);
//dr = dt.NewRow();
//Store the DataTable in ViewState
ViewState["CurrentTable"] = dt;
Gridview1.DataSource = dt;
Gridview1.DataBind();
}
private void AddNewRowToGrid(int visitors)
{
if (ViewState["CurrentTable"] != null)
{
DataTable dtCurrentTable = (DataTable)ViewState["CurrentTable"];
DataRow drCurrentRow;
if (dtCurrentTable.Rows.Count > 0)
{
int rowindex = 0;
for (int i = 1; i < visitors; i++)
{
//extract the TextBox values
TextBox box1 = (TextBox)Gridview1.Rows[rowindex].Cells[1].FindControl("txtDate");
TextBox box2 = (TextBox)Gridview1.Rows[rowindex].Cells[2].FindControl("TextBox2");
TextBox box3 = (TextBox)Gridview1.Rows[rowindex].Cells[3].FindControl("TextBox3");
drCurrentRow = dtCurrentTable.NewRow();
drCurrentRow["RowNumber"] = i + 1;
drCurrentRow["Column1"] = box1.Text;
drCurrentRow["Column2"] = box2.Text;
drCurrentRow["Column3"] = box3.Text;
dtCurrentTable.Rows.Add(drCurrentRow);
drCurrentRow = null;
rowindex++;
}
//add new row to DataTable
//Store the current data to ViewState
ViewState["CurrentTable"] = dtCurrentTable;
//Rebind the Grid with the current data
Gridview1.DataSource = dtCurrentTable;
Gridview1.DataBind();
}
}
else
{
Response.Write("ViewState is null");
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
SetInitialRow();
}
}
Here is problem #1 with your code:
for (int i = dtCurrentTable.Rows.Count; i < visitors; i++)
{
//extract the TextBox values
TextBox box1 = (TextBox)Gridview1.Rows[rowindex].Cells[1].FindControl("txtDate");
TextBox box2 = (TextBox)Gridview1.Rows[rowindex].Cells[2].FindControl("TextBox2");
TextBox box3 = (TextBox)Gridview1.Rows[rowindex].Cells[3].FindControl("TextBox3");
drCurrentRow = dtCurrentTable.NewRow();
drCurrentRow["RowNumber"] = i + 1;
drCurrentRow["Column1"] = box1.Text;
drCurrentRow["Column2"] = box2.Text;
drCurrentRow["Column3"] = box3.Text;
dtCurrentTable.Rows.Add(drCurrentRow);
drCurrentRow = null;
rowindex++;
}
you set i to 1
replace it to row count of gridview
tostart from it
Here is problem #1 with your code:
//extract the TextBox values
TextBox box1 = (TextBox)Gridview1.Rows[rowindex].Cells[1].FindControl("txtDate");
TextBox box2 = (TextBox)Gridview1.Rows[rowindex].Cells[2].FindControl("TextBox2");
TextBox box3 = (TextBox)Gridview1.Rows[rowindex].Cells[3].FindControl("TextBox3");
This logic is flawed and not even necessary, because when you bind the grid it will iterate through the collection you supply as the DataSource and use the TemplateFields you defined in the markup to create each row.
The rows are not actually added to the GridView until is bound to a data source, a DataTable in your case, like this:
Gridview1.DataSource = dt;
Gridview1.DataBind();
Step #1 is to remove the FindControl lines from your AddNewRowToGrid method.
I am not even sure what you are trying to accomplish in your code.