In my Gridview I have the following template field:
<asp:TemplateField HeaderText="Dept Code" SortExpression="DeptCode">
<ItemTemplate>
<%# Eval("DeptCode") %>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="ddlDeptCode" runat="server"
SelectedValue='<%# Eval("DeptCode") %>'
DataSource='<%# GetAllDepartments() %>'
DataTextField="DeptCode"
DataValueField="DeptCode" />
</EditItemTemplate>
</asp:TemplateField>
This works great when I click Edit on a row it populates the DropDownList with all values and selects the correct value for that row.
However, when I try to update the row: OnRowUpdating="UpdateRow"
protected void UpdateRow(object sender, GridViewUpdateEventArgs e)
{
GridViewRow row = UserGV.Rows[e.RowIndex];
DropDownList ddl = row.FindControl("ddlDeptCode") as DropDownList;
string deptCode = ddl.SelectedValue;
}
It finds the DropDownList control but the SelectedValue is always an empty string.
I need access to the selected value to save to the database.
Any ideas as to how I can get the SelectedValue of a DropDownList in a Gridview in code behind?
Edit:
You can also populate the DropDownList and SelectedValue from the code behind:
protected void gv_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if ((e.Row.RowState & DataControlRowState.Edit) > 0)
{
var deptMgr = new DepartmentMgr();
List<Department> departments = deptMgr.GetAllDepartments();
DropDownList ddList = (DropDownList)e.Row.FindControl("ddlDeptCode");
ddList.DataSource = departments;
ddList.DataTextField = "DeptCode";
ddList.DataValueField = "DeptCode";
ddList.DataBind();
string userDeptCode = DataBinder.Eval(e.Row.DataItem, "DeptCode").ToString();
ddList.SelectedItem.Text = userDeptCode;
ddList.SelectedValue = userDeptCode;
}
}
}
I was using a bit of a hack to get a second header for the table title when binding the gridview:
GridViewRow row = new GridViewRow(0, -1, DataControlRowType.Header, DataControlRowState.Normal);
TableCell th = new TableHeaderCell();
th.HorizontalAlign = HorizontalAlign.Center;
th.ColumnSpan = UserGV.Columns.Count;
th.BackColor = Color.SteelBlue;
th.ForeColor = Color.White;
th.Font.Bold = true;
th.Text = "Manage Users";
row.Cells.Add(th);
InnerTable.Rows.AddAt(0, row);
I don't completely understand how this was interfering with getting the SelectedValue of a DropDownList control but as soon as I commented that out it started working.
For those interested I got the second header working with this using a different approach:
In the .aspx file I added this to the Gridview:
OnRowCreated="CreateRow"
And in the code behind I added the following method:
protected void CreateRow(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Header)
{
GridView gridView = (GridView)sender;
GridViewRow row = new GridViewRow(1, 0, DataControlRowType.Header, DataControlRowState.Normal);
TableCell th = new TableHeaderCell();
th.HorizontalAlign = HorizontalAlign.Center;
th.ColumnSpan = UserGV.Columns.Count;
th.ForeColor = Color.White;
th.BackColor = Color.SteelBlue;
th.Font.Bold = true;
th.Text = "Manage Users";
row.Cells.Add(th);
gridView.Controls[0].Controls.AddAt(0, row);
}
}
Everything is working correctly now.
In the edit template, set the selectedvalue from the data bindings, then you will get the correct selected value instead of a null.
SelectedValue='<%# Bind("DeptCode") %>'
Related
I am creating dynamic Template Fields for my gridview:
<asp:GridView ID="grdData" runat="server" DataKeyNames = "ID" AutoGenerateColumns="false" OnRowDataBound="grdData_RowDataBound">
<Columns>
<asp:TemplateField>
<HeaderTemplate>
<asp:CheckBox ID="chkAll" AutoPostBack="true" OnCheckedChanged="OnCheckedChanged" runat="server" />
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox ID="editbtn" AutoPostBack="true" OnCheckedChanged="OnCheckedChanged" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
the code to add templateField is below:
private void BindGridView(DataTable dtData)
{
foreach (DataColumn item in dtData.Columns)
{
TemplateField tfield = new TemplateField();
tfield.HeaderText = item.ToString();
grdData.Columns.Add(tfield);
}
grdData.DataSource = dtData;
ViewState["dtDataTable"] = dtData;
grdData.DataBind();
}
and in row databound I am adding textbox and label to the templatefield:
protected void grdData_RowDataBound(object sender, GridViewRowEventArgs e)
{
DataTable dtData = (DataTable)ViewState["dtDataTable"];
if (e.Row.RowType == DataControlRowType.DataRow)
{
int i = 1;
foreach (DataColumn item in dtData.Columns )
{
TextBox txtBox = new TextBox();
txtBox.ID = "txt"+item.ToString();
txtBox.Text = (e.Row.DataItem as DataRowView).Row[item.ToString()].ToString();
txtBox.Visible = false;
e.Row.Cells[i].Controls.Add(txtBox);
Label lblBox = new Label();
lblBox.ID = "lbl" + item.ToString();
lblBox.Text = (e.Row.DataItem as DataRowView).Row[item.ToString()].ToString();
e.Row.Cells[i].Controls.Add(lblBox);
i++;
}
}
}
Everything is working good so far,The grid is getting created and the values are getting populated ,but when i am calling below method and try to access the gridview control ,its throwing object reference error:
protected void OnCheckedChanged(object sender, EventArgs e)
{
bool isUpdateVisible = false;
CheckBox chk = (sender as CheckBox);
if (chk.ID == "chkAll")
{
foreach (GridViewRow row in grdData.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
row.Cells[0].Controls.OfType<CheckBox>().FirstOrDefault().Checked = chk.Checked;
}
}
}
CheckBox chkAll = (grdData.HeaderRow.FindControl("chkAll") as CheckBox);
chkAll.Checked = true;
foreach (GridViewRow row in grdData.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
bool isChecked = row.Cells[0].Controls.OfType<CheckBox>().FirstOrDefault().Checked;
for (int i = 1; i < row.Cells.Count; i++)
{
Label test= row.FindControl("lblName") as Label;//this is coming null
Below code lines are throwing object reference error as they are not able to find control
row.Cells[i].Controls.OfType<Label>().FirstOrDefault().Visible = !isChecked;//this line throwing object reference error
if (row.Cells[i].Controls.OfType<TextBox>().ToList().Count > 0)
{
row.Cells[i].Controls.OfType<TextBox>().FirstOrDefault().Visible = isChecked;
}
if (row.Cells[i].Controls.OfType<DropDownList>().ToList().Count > 0)
{
row.Cells[i].Controls.OfType<DropDownList>().FirstOrDefault().Visible = isChecked;
}
if (isChecked && !isUpdateVisible)
{
isUpdateVisible = true;
}
if (!isChecked)
{
chkAll.Checked = false;
}
}
}
}
btnUpdate.Visible = isUpdateVisible;
}
Edit:
I tried reinistialising the controls in preinit event but still no luck:
protected void Page_PreInit(object sender, EventArgs e)
{
if (ViewState["gridData"] != null)
{
BindGridView((DataTable)ViewState["gridData"]);
}
}
What I am doing wrong?
I recreated the dynamic gridview Controls in OnRowCreated as this event gets called in every postback instead of onRowDataBound Event and it worked like charm.
When AllowPaging is enabled in a GridView, you can set 4 different types of display modes in the PagerSettings.
<PagerSettings Mode="NextPreviousFirstLast" FirstPageText="First" LastPageText="Last" PageButtonCount="5" Position="Bottom" />
These types are
NextPrevious : Previous-page and next-page buttons.
NextPreviousFirstLast: Previous-page, next-page, first-page, and last-page buttons.
Numeric : Numbered link buttons to access pages directly.
NumericFirstLast : Numbered and first-link and last-link buttons.
Which will look like this
< >
Fist < > Last
1 2 3 4
1 2 3 4 Last
But what I want is all the page numbers and then a "View All" or "Show All" button to display all the Grid rows.
1 2 3 4 - Show All
Is this possible?
Yes it is. The trick is that the GridView Pager Control is a nested table inside the GridView. You can use the OnRowCreated event to find that table and add you own "Show All" link.
That link will trigger a command that sets the AllowPaging property to false thus showing all the rows.
This will work for every GridView on the page, just add the OnRowCreated event to the GridView.
<asp:GridView ID="GridView1" runat="server" OnRowCreated="pagerViewAll_RowCreated">
And then in code behind
protected void pagerViewAll_RowCreated(object sender, GridViewRowEventArgs e)
{
//check if the row is the pager row
if (e.Row.RowType == DataControlRowType.Pager)
{
//cast the sender back to a gridview
GridView gridView = sender as GridView;
//get the id of the gridview as a string
string senderID = gridView.ID;
//create a new linkbutton
LinkButton linkButton = new LinkButton();
linkButton.ID = senderID + "_ShowAll";
linkButton.Text = "Show All";
linkButton.CommandName = senderID;
//add the viewAll_Command to the linkbutton
linkButton.Command += new CommandEventHandler(viewAll_Command);
//get the first table cell from the pager row (there is only one, spanned across all colums)
TableCell pagerCell = e.Row.Cells[0];
//cast the first control found in the pager cell as a table
Table table = pagerCell.Controls[0] as Table;
//then the first row of the table containing the pager buttons
TableRow row = table.Rows[0];
//add an empty cell for spacing
TableCell tableCellSpacer = new TableCell();
tableCellSpacer.Text = " - ";
row.Cells.Add(tableCellSpacer);
//then add the cell containing the view all button
TableCell tableCell = new TableCell();
tableCell.Controls.Add(linkButton);
row.Cells.Add(tableCell);
}
}
The View All Method in code behind
protected void viewAll_Command(object sender, CommandEventArgs e)
{
//check which gridview for setting all the rows visible
if (e.CommandName == "GridView1")
{
//disable pagination and rebuild the grid
GridView1.AllowPaging = false;
buildGridView1();
}
else if (e.CommandName == "GridView2")
{
GridView2.AllowPaging = false;
buildGridView2();
}
else if (e.CommandName == "ListView1")
{
DataPager dataPager = ListView1.FindControl("DataPager1") as DataPager;
dataPager.PageSize = 99999;
buildListView1();
}
}
This also works for a DataPager Control used in ListView for example.
private void extendDataPagerInListView()
{
//find the datapager inside the listview
DataPager dataPager = ListView1.FindControl("DataPager1") as DataPager;
//get the id of the listview as a string
string senderID = ListView1.ID;
//add some spacing
Literal literal = new Literal();
literal.Text = " - ";
//add the literal to the datapager
dataPager.Controls.Add(literal);
//create a new linkbutton
LinkButton linkButton = new LinkButton();
linkButton.ID = senderID + "_ShowAll";
linkButton.Text = "Show All";
linkButton.CommandName = senderID;
//add the viewAll_Command to the linkbutton
linkButton.Command += new CommandEventHandler(viewAll_Command);
//add the linkbutton to the datapager
dataPager.Controls.Add(linkButton);
}
Below is how my GridView code , since the datatable is a pivoted value so the number of columns cannot be predicted. So I am adding textbox dynamically through code.
<asp:GridView ID="gvData"
EmptyDataText="There are no data records to display."
runat="server" AutoGenerateColumns="false"
HeaderStyle-BackColor="#3AC0F2"
HeaderStyle-ForeColor="White" OnRowDataBound="gvData_RowDataBound" >
<RowStyle BorderColor="LightBlue" />
</asp:GridView>
protected void Page_Load(object sender, EventArgs e)
{
foreach (var item in columnNames)
{
TemplateField tfield = new TemplateField();
tfield.HeaderText = item;
gvData.Columns.Add(tfield);
}
gvData.DataSource = ds.Tables[0];
gvData.DataBind();}
protected void gvData_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
for (int i = 3; i < columnNames.Length; i++)
{
TextboxCount++;
TextBox txtName = new TextBox();
txtName.ID = "txt" + Convert.ToString(TextboxCount);
txtName.BorderStyle = BorderStyle.None;
txtName.Text = (e.Row.DataItem as DataRowView).Row[columnNames[i]].ToString();
e.Row.Cells[i].Controls.Add(txtName); }}}
Now when user try to change value in the textbox I have to validate that they only enter integer value.
Here I am not sure what has to be done.
You can use int.TyrParse method
Example
int number;
string s = "AA";
bool IsInteger = int.TryParse(s, out number);
You could use javascript function and that to textbox from code behind like:
// Add this gvData_RowDataBound , allownumbers is a javascript function
txtName.Attributes.Add("onkeypress", "javascript:return allownumbers(event);");
Or else if you are using .NET 4.5 version then try out this:
txtName.Attributes["type"] = "number";
This is my code behind code. I want to populate the DropDownList once the user clicked edit but the DropDownList I'm getting is null. Why?
protected void SupportSchedule_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "EditRow")
{
int rowIndex = ((GridViewRow)((ImageButton) e.CommandSource).NamingContainer).RowIndex;
GridViewRow row = (GridViewRow)(((ImageButton) e.CommandSource).NamingContainer);
SupportScheduleTable.EditIndex = rowIndex;
shift.Enabled = true;
resourcedate.Enabled = true;
ListItemCollection c = db.fillList();
DropDownList ddl1 = row.FindControl("ddlshiftmanager") as DropDownList;
DropDownList ddl2 = row.FindControl("ddldispatcherone") as DropDownList;
DropDownList ddl3 = row.FindControl("ddldispatchertwo") as DropDownList;
if (c != null && ddl1 != null)
{
ddl1.DataSource = c;
ddl2.DataSource = c;
ddl3.DataSource = c;
ddl1.DataBind();
ddl2.DataBind();
ddl3.DataBind();
}
getSupportSchedule();
}
else if (e.CommandName == "CancelUpdate")
{
//some codes here
} else if (e.CommandName == "UpdateRow")
{
//some codes here
}
}
//asp code
<asp:GridView ID="SupportScheduleTable" AutoGenerateColumns="False" Width="100%" runat="server" OnRowCommand="SupportSchedule_RowCommand">
<Columns>
<asp:TemplateField HeaderText="Shift Manager">
<EditItemTemplate>
<asp:DropDownList ID="ddlshiftmanager" runat="server" Width="99%"></asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("shift_manager") %>'></asp:Label>
</ItemTemplate>
<HeaderStyle Width="32%" />
</asp:TemplateField>
<asp:TemplateField ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:ImageButton ID="lbEdit" CssClass="btn" ImageUrl="~/Files/edit.png" CommandArgument='<%# Eval("support_schedule_id") %>' CommandName="EditRow" runat="server"></asp:ImageButton>
</ItemTemplate>
<EditItemTemplate>
<asp:LinkButton ID="lbUpdate" CommandArgument='<%# Eval("support_schedule_id") %>' CommandName="UpdateRow" runat="server">Update</asp:LinkButton>
<asp:LinkButton ID="lbCancel" CommandArgument='<%# Eval("support_schedule_id") %>' CommandName="CancelUpdate" runat="server" CausesValidation="false">Cancel</asp:LinkButton>
</EditItemTemplate>
<HeaderStyle Width="2%" />
</asp:TemplateField>
//two dropdownlists before image button
</Columns>
</GridView>
I just added the ImageButton here in the recent update but this is my original code that doesn't work.
I used a SqlDataSource instead of adding the list items from the back
and this is what I used to get the selected value of the DropDownList.
else if (e.CommandName == "UpdateRow")
{
int rowIndex = ((GridViewRow)((LinkButton)e.CommandSource).NamingContainer).RowIndex;
DropDownList ddlshift = (DropDownList)SupportScheduleTable.Rows[rowIndex].FindControl("ddlshiftmanager");
DropDownList ddlone = (DropDownList)SupportScheduleTable.Rows[rowIndex].FindControl("ddldispatcherone");
DropDownList ddltwo = (DropDownList)SupportScheduleTable.Rows[rowIndex].FindControl("ddldispatchertwo");
string manager = ddlshift.SelectedValue;
string one = ddlone.SelectedValue;
string two = ddltwo.SelectedValue;
int supportID = Convert.ToInt32(e.CommandArgument);
String sh = shift.Text;
String date = resourcedate.Text;
db.updateSS(supportID, sh, manager, one, two,date);
SupportScheduleTable.EditIndex = -1;
shift.Enabled = false;
resourcedate.Enabled = false;
getSupportSchedule();
}
Your answer is a correct way to handle the issue you are seeing. But, in case you didn't figure out the actual cause...
The ImageButton you click is in your ItemTemplate. The DropDownList you want to bind is in your EditItemTemplate. lbEdit exists when you are not in edit mode but ddlshiftmanager only exists when you are.
So, the fix is to put the GridView in edit mode. Notice that this is something you actually already started to do. You need to set the EditIndex, re-bind the GridView, then get the row again. You'll then have the row in edit mode. This row should now contain ddlshiftmanager.
protected void SupportSchedule_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "EditRow")
{
int rowIndex = ((GridViewRow)((ImageButton) e.CommandSource).NamingContainer).RowIndex;
// Set the index to edit
SupportScheduleTable.EditIndex = rowIndex;
// Re-bind the GridView to put it in edit mode
SupportScheduleTable.DataSource = /* your data source */
SupportScheduleTable.DataBind();
// Get the row at the index. The row will be the
// row reflected in edit mode.
GridViewRow editRow = SupportScheduleTable.Rows[rowIndex];
// Find your DropDownLists in this edit row
DropDownList ddl1 = editRow.FindControl("ddlshiftmanager") as DropDownList;
DropDownList ddl2 = editRow.FindControl("ddldispatcherone") as DropDownList;
DropDownList ddl3 = editRow.FindControl("ddldispatchertwo") as DropDownList;
shift.Enabled = true;
resourcedate.Enabled = true;
ListItemCollection c = db.fillList();
if (c != null && ddl1 != null)
{
ddl1.DataSource = c;
ddl2.DataSource = c;
ddl3.DataSource = c;
ddl1.DataBind();
ddl2.DataBind();
ddl3.DataBind();
}
getSupportSchedule();
}
// Everything else...
}
I have been struggling with this for a while now.
I want to dynamically create data columns using the entity framework.
var query2 = (from c in dbc.FridayTimeSlots
where c.RoundType == "Back 9"
select c);
grvF2.Columns.Clear();
grvF2.DataSource = query2.ToList();
grvF2.Columns.Add(new BoundField { DataField = "TeeTime", HeaderText = "Tee-Off Time" });
grvF2.Columns.Add(new CommandField { HeaderText = "Select", SelectText = "Select Time", ButtonType = ButtonType.Link, ShowSelectButton = true });
grvF2.DataKeyNames = new string[] { "TimeID" };
grvF2.DataBind();
My problem, I want to only display the command field when the data field TeeTime = "something" and when TeeTime = "somethinig else" I don't want the commandfield there.
If tried just about everything but I can't get the solution.
Any help would be greatly appreciated.
In GridView's RowDataBound you can find the LinkButton and make Visible=false:
protected void grvF2_RowDataBound(object sender, GridViewRowEventArgs e)
{
GridViewRow gvr = e.Row as GridViewRow;
if (gvr != null && gvr.RowType == DataControlRowType.DataRow)
{
LinkButton lb = gvr.Cells[1].Controls[0] as LinkButton;
if (lb != null && gvr.Cells[0].Text.ToLower() != "something")
{
lb.Visible = false;
}
}
}
Assuming that you have this markup for the GridView:
<asp:GridView ID="grvF2" runat="server"
AutoGenerateColumns="false" OnDataBound="grvF2_DataBound"
OnRowDataBound="grvF2_RowDataBound" >
</asp:GridView>
And the output may look like: