Can't find dropdown list in RowDataBound event - asp.net

I'm following this example http://www.codeproject.com/KB/webforms/Editable_GridView.aspx to build an editable GridView control.
I have this code in my GridView:
<asp:TemplateField HeaderText="Negócio">
<ItemTemplate>
<asp:Label ID="lblNegocio" runat="server" Text='<%# Eval("Negocio") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="ddlNegocio" runat="server" />
</EditItemTemplate>
<FooterTemplate>
<asp:DropDownList ID="ddlNewNegocio" runat="server" />
</FooterTemplate>
Now, I'm trying to fill the dropdown in the EditItemTemplate with some dynamic values just as the example says, in the RowDataBound Event of the grid. But when I do this, the FindControl method always returns Nothing:
Protected Sub gdvRegraRotationDefault_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gdvRegraRotationDefault.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
Dim ddlNegocio As DropDownList = e.Row.FindControl("ddlNegocio")
End If
End Sub
If I can't find the Dropdown I can't load the values in it and when I'm going to edit de entry it will be empty.
Can someone help me?
Thank you (:

Please use the RowEditing-Event, as your DropDownList should only be shown when clicking Edit.
But first, you have to bind the GridView newly as the GridView now needs to render different controls for the edit row:
protected void gdvRegraRotationDefault_RowEditing(object sender, GridViewEditEventArgs e)
{
gdvRegraRotationDefault.EditIndex = e.NewEditIndex;
gdvRegraRotationDefault.DataBind();
GridViewRow row = gdvRegraRotationDefault.Rows[e.NewEditIndex];
DropDownList ddl = row.FindControl("ddlNegocio") as DropDownList;
//now do databinding for DropDownList
}

The FindControl always return null because when your in the RowDataBound event you can get the label only.
If you want to fill the DropDownList when you click the edit button on the grid, then you have to use the GridViewRowEditing event.

In the RowDataBound event, simply add the following conditional:
if (myGridView.EditIndex == e.Row.RowIndex)
{
//do work
}

Related

Iterating through EditItemTemplate textboxes in asp:Gridview

I have a gridview displaying data within a template field which requires more information about the record to be displayed by clicking on a linkbutton. Right now, I have the "details" linkbutton display the information by calling the edit command on the gridview so that it switches to the EditItemTemplate. Within the EditItemTemplate I have a linkbutton for cancel and then an edit button that, when clicked, displays the update button with the update command, but I need it to iterate through that row and set all the textboxes within the EditItemTemplate to ReadOnly=false so as to allow them to be edited before the update command is selected. Here is a summary of the code:
<ItemTemplate>
*basic information displayed*
<asp:LinkButton runat="server" CommandName="Edit" Text="Details"></asp:LinkButton>
</ItemTemplate>
<EditItemTemplate>
*A bunch of readonly textboxes that display the extra information*
<asp:LinkButton runat="server" CommandName="Update" Text="Update" Visible="false"></asp:LinkButton>
<asp:LinkButton runat="server" Text="Edit" OnClick="editButton_Click"></asp:LinkButton>
</EditItemTemplate>
And the code for the event which makes the buttons appear the way I want, but I'm not sure how to iterate through the EditItemTemplate, or even if this is what I should do:
Protected Sub editButton_Click(sender As Object, e As EventArgs)
sender.FindControl("updateButton").Visible = True
sender.FindControl("editbutton").Visible = False
For Each t In ?EditItemTemplate?
Dim textbox = TryCast(t, System.Web.UI.WebControls.TextBox)
If textbox IsNot Nothing Then
textbox.ReadOnly = False
End If
Next
End Sub
So my question is either how to get this to work, or how I should set up the GridViewCommands otherwise
You should use a PlaceHolder in your EditItemTemplate. Place all of your Controls/LinkButtons inside this placeholder.
<EditItemTemplate>
<asp:PlaceHolder ID="TestPlaceHolder" runat="server">
// Sample Link Buttons
<asp:LinkButton runat="server" CommandName="Update" Text="Update"
Visible="false"></asp:LinkButton>
<asp:LinkButton runat="server" Text="Edit" OnClick="editButton_Click"></asp:LinkButton>
// Sample Text Box
<asp:TextBox runat="server" ID="FirstName" ...>...</TextBox>
</asp:PlaceHolder>
</EditItemTemplate>
Handle the RowEditing event of GridView. Inside the edit event handler, first find the Placeholder, then use the PlaceHolder's Controls property to iterate over the Controls...
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
// Get the Placeholder for the row being edited.
PlaceHolder testPlacehldr =
GridView.Rows[e.NewEditIndex].FindControl("TestPlaceholder") as PlaceHolder;
// Iterate over the controls
if(testPlacehldr.Controls.Count > 0)
{
foreach (Control ctrl in testPlacehldr.Controls)
{
if (ctrl is LinkButton)
{
LinkButton lnkBtn = ctrl as LinkButton
if(lnkBtn.Text== "Update")
{
lnkBtn.Visible = false;
}
// More IF conditions follow....
}
if (ctrl is TextBox)
{
TextBox txtBox = ctrl as TextBox;
if(txtBox.ID == "FirstName")// use any property of TexBox you prefer
{
txtBox.ReadOnly= true;
}
// More IF conditions follow....
}
}
}
//At the End, set the EditIndex and Bind the data
GridView1.EditIndex = e.NewEditIndex;
BindGridViewData();
}
I hope you can workout the logic yourself now for hiding/showing the controls.
So I figured out how to do it (needed it in vb) by using the placeholder within the EditItemTemplate, here's the code behind it:
Protected Sub editButton_Click(sender As Object, e As EventArgs)
sender.FindControl("editbutton").Visible = False
sender.FindControl("updateButton").Visible = True
Dim testPlacehldr As PlaceHolder = sender.FindControl("TestPlaceholder")
If testPlacehldr.Controls.Count > 0 Then
Dim btn As LinkButton = sender.FindControl("editButton")
If btn.Visible = False Then
For Each ctrl As Control In testPlacehldr.Controls
If ctrl.GetType Is GetType(TextBox) Then
Dim box As TextBox = TryCast(ctrl, TextBox)
box.ReadOnly = False
End If
Next
End If
End If
End Sub
This works fine for what I need it to do. Credit to the user R.C. for the idea about placeholders

pass ID value to OnCheckedChange event in code behind

I have a gridview that has one checkbox for each row of data.
When the checkbox is checked or unchecked, I need to update a bit flag in my database.
I'm trying to use the OnCheckedChanged event.
It does fire, however I am getting a null error which has to do with an ID.
My problem is, I'm not quite sure how to get the needed ID to the OnCheckedChanged event code.
I need this ID to update the appropriate row in my database.
I found a few relavent questions on StackOverflow but none of the supplied answers really helped me out.
Thanks!
My gridview code:
<asp:GridView ID="gvlisting" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField HeaderText="Item Is Ready">
<ItemTemplate>
<asp:CheckBox ID="isReady" runat="server" AutoPostBack="true" OnCheckedChanged="isReady_CheckedChanged" Checked='<%#isReady(CInt(Eval("isReady")))%>'/>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Item Name">
<ItemTemplate>
<asp:Label ID="itemName" runat="server" Text='<%#cleanString(Eval("itemName").ToString())%>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
code behind:
Public Sub isReady_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs)
Dim box As CheckBox = DirectCast(sender, CheckBox)
If box.Checked = True Then
'custom code for executing an SQL UPDATE statement
db.ExecuteNonQuery(AddIsreadyFlag, New SqlParameter("#itemID", Me.ID))
Else
db.ExecuteNonQuery(RemoveIsreadyFlag, New SqlParameter("#itemID", Me.ID))
End If
End Sub
Me.ID is the ID of the Page since Me is the current page-instance.
You could add another template-field with the ID:
<asp:TemplateField HeaderText="Item-ID" Visible="false">
<ItemTemplate>
<asp:Label ID="itemID" runat="server" Text='<%# Eval("itemID") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
Now you can use the NamingContainer to get the row and FindControl to get the label:
Public Sub isReady_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs)
Dim box As CheckBox = DirectCast(sender, CheckBox)
Dim row = DirectCast(box.NamingContainer, GridViewRow)
Dim itemID = DirectCast(row.FindControl("itemID"), Label).Text
If box.Checked = True Then
'custom code for executing an SQL UPDATE statement
db.ExecuteNonQuery(AddIsreadyFlag, New SqlParameter("#itemID", itemID))
Else
db.ExecuteNonQuery(RemoveIsreadyFlag, New SqlParameter("#itemID", itemID))
End If
End Sub
You can also try to add a custom attribute in the OnDataBinding event and retrieve the value in de CheckChanged event.
protected void chkEnabled_DataBinding(object sender, EventArgs e)
{
CheckBox chk = (CheckBox)sender;
string id = Eval("Id").ToString();
chk.Attributes.Add("data-id", id);
}
protected void chkEnabled_CheckedChanged(object sender, EventArgs e)
{
CheckBox chk = (CheckBox)sender;
string id = chk.Attributes["data-id"];
}
Add the ID column to the grid, then if needed set it's visible property to false.
You can get the Gridview's selected row then get cell the value for ID column (the column does not need to be visisble, but it needs to exist in the grid).
var someVar = gvlisting.SelectedRow.Cells[0].Text; //change 0 to correct column
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.selectedrow(v=vs.110).aspx
You may need to do this in a SelectedIndexChanged but i doubt that, if that is the case you can easily get the data from the cell using the above or findcontrol like...How to find control in TemplateField of GridView?

Gridview template radiobuttonlist SelectedInxedChanged, Getting the row the list was in when it fired

I have a Gridview in which one of the template fields has a radiobuttonlist and a dropdownlist. How can I access the row that the radiobuttonlist is in on the SelectedIndexChanged event, so I don't end up updating all of the dropdownlist inside the that template field of the gridview. I don't have any code currently but any help would be greatly appreciated
<asp:TemplateField HeaderText="Column with ListControls" >
<ItemTemplate>
<asp:DropDownList ID="DropdownList1" OnSelectedIndexChanged="SomethingChanged" AutoPostBack="true" runat="server" >
<asp:ListItem Text="1"></asp:ListItem>
<asp:ListItem Text="2"></asp:ListItem>
</asp:DropDownList>
<asp:RadioButtonList ID="RadioButtonList1" OnSelectedIndexChanged="SomethingChanged" AutoPostBack="true" runat="server">
<asp:ListItem Text="1"></asp:ListItem>
<asp:ListItem Text="2"></asp:ListItem>
</asp:RadioButtonList>
</ItemTemplate>
</asp:TemplateField>
Codebehind VB.NET:
Protected Sub SomethingChanged(ByVal sender As Object, ByVal e As EventArgs)
'in this example this handler is used for both, Dropdownlist and RadiobuttonList'
Dim listControl = DirectCast(sender, ListControl)
Dim row = DirectCast(listControl.NamingContainer, GridViewRow)
Dim item = listControl.SelectedItem
'with FindControl on the row you could also find controls in other columns...'
End Sub
C#:
protected void SomethingChanged(object sender, EventArgs e)
{
//in this example this handler is used for both, Dropdownlist and RadiobuttonList
var listControl = (ListControl)sender;
var row = (GridViewRow)listControl.NamingContainer;
var item = listControl.SelectedItem;
//with FindControl on the row you could also find controls in other columns...
}

ASP.NET - GridView - How to programmatically add and read new controls to the cell?

Here is the setup:
I programmatically populate my gridview using LINQ to SQL query. Then I enter the edit mode and want to replace some standard TextBox controls with DropDownLists like this:
'excerpt from GridView1_RowEditing
Dim ddlist1 As New DropDownList
Dim res1 = From items1 In mydb.Items
Select items1.Col10
ddlist1.DataSource = res1
ddlist1.DataBind()
GridView1.Rows.Item(0).Cells(1).Controls.Add(ddlist1)
At this moment I have my gridview showing standard textbox control and new DDList control (in the Column 1).
The problem is -- I cant read the value from DDList in the RowUpdating method. It seems like DDList control is not in the GridView1.Rows.Item(0).Cells(1).Controls collection.
RowUpdating method sees only standard TextBox control and can read it's value.
Any suggestions are welcome. I just don't understand something here :(
Use TemplateField, and then you can locate your dropdown using FindControl
<asp:GridView ID="GridView1" runat="server">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="DropDownList1" runat="server">
</asp:DropDownList>
</EditItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
...
Protected Sub GridView1_RowUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewUpdateEventArgs) Handles GridView1.RowUpdating
Dim ddl = CType(GridView1.Rows(e.RowIndex).Cells(1).FindControl("DropDownList1"), DropDownList)
End Sub

Problem finding a control within a FormView from code-behind

Here the code behind... I'm trying to retrieve this control so I can add items to the drop down list (I'm retrieving the Role Groups to add to the drop down list in the code-behind)
Protected Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim DDRoleGroups As DropDownList
DDRoleGroups = FormView1.FindControl("DDRoleGroup")
End Sub
Here's the FormView: (I took out most of the fields so it's easier to read)
<asp:FormView ID="FormView1" runat="server" DataKeyNames="ID"
DataSourceID="ObjectDataSource_Vendors"
DefaultMode="Insert" BorderColor="DarkGray"
BorderStyle="Solid" BorderWidth="1px" CellPadding="4" Visible="False">
<EditItemTemplate>
</EditItemTemplate>
<InsertItemTemplate>
<label class="form_label">Role Group:</label><br /><asp:DropDownList ID="DDRoleGroup"
runat="server" Width="175px"
EnableViewState="False">
</asp:DropDownList>
</InsertItemTemplate>
</asp:FormView>
Could it possibly have to do with the fact that it's in the Page_Load sub and the control hasn't acctually loaded yet?
Thanks,
Matt
Your dropdown only exists in Insert mode. Try to implement the formview's ModeChanged event and retrieve the control if CurrentMode == Insert:
protected void FormView1_ModeChanged(object sender, EventArgs e)
{
if (FormView1.CurrentMode == FormViewMode.Insert)
{
DropDownList DDRoleGroups = FormView1.FindControl("DDRoleGroup");
// fill dropdown
}
}
You cannot handle this in Page_Load, as the form has not yet switched into Insert mode.
FindControl on a formview will only work for the template that the FormView's "CurrentMode" property is set to.
In your case, you can only do FindControl for "DDRoleGroups" if your FormView is set to "Insert", since that's the template that your control exists in.
Hope that helps.

Resources