Binding a DropDownList inside a DetailsView - c#

I'm having problems trying to populate a dropdownlist from the database. When I'm trying to set the datasource I can't find the dropdown control, it's in a DetailsView so I think it might have something to do with it only being created when it's in edit mode. It still says it's in current mode when I'm editing though, so not sure what's going on there.
Here's the code from the aspx file:
<asp:DetailsView id="DetailsView1" runat="server" AutoGenerateRows="false" DataSourceID="myMySqlDataSrc" DataKeyNames="id" AutoGenerateDeleteButton="True" AutoGenerateEditButton="True" AutoGenerateInsertButton="False" >
<Fields>
<asp:TemplateField HeaderText="Region">
<ItemTemplate><%# Eval("region_name") %></ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="RegionDropdownList" runat="server" SelectedValue='<%# Bind("region_id")%>' />
</EditItemTemplate>
</asp:TemplateField>
</Fields>
</asp:DetailsView>
And this is from the code behind:
ArrayList regionsList = BPBusiness.getRegions();
if (DetailsView1.CurrentMode == DetailsViewMode.Edit)
{
DropDownList ddlRegions = (DropDownList)DetailsView1.FindControl("RegionDropdownList");
if (ddlRegions != null)
{
ddlRegions.DataSource = regionsList;
ddlRegions.DataBind();
}
}

If it isn't already, place the sample from your code behind inside the DetailsView1_ModeChanged or DetailsView1_DataBound method. If it is in the DetailsView1_ModeChanging method, the mode has not actually changed yet.
EDIT: Also, make sure you set up the DataTextField and DataValueField like so:
DropDownList1.DataTextField = "TextFieldName";
DropDownList1.DataValueField = "ValueFieldName";
Also remove the SelectedValue bind; it does nothing except throw errors.
EDIT 2: If you really need to select a particular value of the dropdownlist when it first is databind, you could do something like this:
if(DropDownList1.Items.Contains(DropDownList1.Items.FindByValue("Value")))
{
DropDownList1.SelectedIndex = DropDownList1.Items.IndexOf(DropDownList1.Items.FindByValue("Value));
}

try doing it in the itemcreated method
protected void DetailsView1_ItemCreated(object sender, EventArgs e)
{
ArrayList regionsList = BPBusiness.getRegions();
if (DetailsView1.CurrentMode == DetailsViewMode.Edit)
{
DropDownList ddlRegions = (DropDownList)DetailsView1.FindControl("RegionDropdownList");
if (ddlRegions != null)
{
ddlRegions.DataSource = regionsList;
ddlRegions.DataBind();
}
}
}
remember to set OnItemCreated="DetailsView1_ItemCreated"

Related

Retrieve values from GridView by changing a value in a DropDownList

I'm having problems retrieving the current row by changing the status of a DropDownList in the row. My code for the GridView is:
<asp:GridView ID="grdMappingList" runat="server" OnPageIndexChanging="grdMappingList_PageIndexChanging" AutoGenerateColumns="false" AllowPaging="true" PageSize="10" ShowHeaderWhenEmpty="true" UseAccessibleHeader="true" CssClass="table table-hover table-striped segment_list_tbl" >
<PagerStyle CssClass="grid_pagination" HorizontalAlign="Right" VerticalAlign="Middle" BackColor="#DFDFDF" />
<Columns>
<asp:BoundField HeaderText="Mapping Id" DataField="MAPPING_ID"></asp:BoundField>
<asp:BoundField HeaderText="PDM Name" DataField="PDM_NAME"></asp:BoundField>
<asp:BoundField HeaderText="PDM EntityID" DataField="PDM_ENTITY_ID" Visible="false"></asp:BoundField>
<asp:TemplateField HeaderText="Mapping Status" HeaderStyle-CssClass="width_120 aligned_center" ItemStyle-CssClass="width_120 aligned_center" Visible="true">
<ItemTemplate>
<asp:DropDownList id="ddlMappingStatus" runat="server" SelectedValue='<%# Bind("MappingCompleted") %>' OnSelectedIndexChanged="ddlMappingStatus_SelectedIndexChanged" AutoPostBack="true">
<asp:ListItem Text="Done" Value="DONE"></asp:ListItem>
<asp:ListItem Text="Not Done" Value="NOT DONE"></asp:ListItem>
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And the code behind is:
protected void ddlMappingStatus_SelectedIndexChanged(object sender, EventArgs e)
{
int MappingID = Convert.ToInt16(grdMappingList.SelectedRow.Cells[0].Text);
DropDownList ddgvOpp = (DropDownList)grdMappingList.SelectedRow.FindControl("ddlMappingStatus");
if (ddgvOpp.Equals("DONE"))
{
}
}
I am getting an error on this line:
DropDownList ddgvOpp (DropDownList)grdMappingList.SelectedRow.FindControl("ddlMappingStatus");
and this line:
int MappingID = Convert.ToInt16(grdMappingList.SelectedRow.Cells[0].Text);
It seems that I can't retrieve the values! I dont know why. When I choose a new status from the DropDownList, I want to get all the values of the row in order to update the record.
Unfortunately, SelectedRow does not mean what you think it means. It doesn't just simply mean the current row you are working on or the current row with the controls that you are using. That property must get set somehow. This is usually done through a "Select" button on the GridView, such as an <asp:ButtonField> with the command name "Select".
You really do not need this however. You just need the row you are working with. Since you are using the SelectedIndexChanged event of your DropDownList, you already have what you need. You just need to go about it a different way.
First, get the DropDownList. Then get the row of the DropDownList. Now do whatever you need with the row.
But, from your code, it looks like you may not even need the row. You just need the value of the DropDownList. So you could skip that all together. But if you do need the row, here is how you would do that too.
protected void ddlMappingStatus_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList ddlMappingStatus = (DropDownList)sender;
if(ddlMappingStatus.SelectedItem.Text.ToUpper() == "DONE")
{
}
GridViewRow row = (GridViewRow)ddlMappingStatus.NamingContainer;
}
Now when you use <asp:BoundField> controls in your GridView, getting their values isn't very clean. You are forced to hardcode the column index like you were doing:
GridViewRow row = (GridViewRow)ddlMappingStatus.NamingContainer;
String mappingID = row.Cells[0].Text;
I tend to prefer using <asp:TemplateField> controls so I can use FindControl() to get what I am after. This prevents any reordering of the columns from breaking the code, as you'd have to hardcode different indexes. So for example, to find that DropDownList (since it already is a <asp:TemplateField>), you'd do something like this:
DropDownList ddlMappingStatus = (DropDownList)row.FindControl("ddlMappingStatus");

Nesting Gridview inside Formview breaks insert codebehind context

I have a couple of GridViews in my FormView page and I am wanting to make an Insert row in the FooterRow of the Gridviews. Layout and everything is fine. However, as I'm building the codebehind for the Insert command, I'm running into a context problem. If I move the GridView outside of the FormView markup, the context errors clear up immediately.
GridView Markup
<asp:GridView ID="gvBFMats" runat="server" ShowFooter="True" AutoGenerateColumns="False" DataKeyNames="MaterialID" DataSourceID="BFMatsSQL" OnRowCommand="gvBFMats_RowCommand">
<Columns>
<asp:TemplateField HeaderText="Commands" ShowHeader="False">
<EditItemTemplate>
<asp:LinkButton ID="ButtonUpdate" runat="server" CausesValidation="True" CommandName="Update" Text="Update"></asp:LinkButton>
<asp:LinkButton ID="LinkButton2" runat="server" CausesValidation="False" CommandName="Cancel" Text="Cancel"></asp:LinkButton>
</EditItemTemplate>
<ItemTemplate>
<asp:LinkButton ID="ButtonEdit" runat="server" CausesValidation="False" CommandName="Edit" Text="Edit"></asp:LinkButton>
<asp:LinkButton ID="ButtonDelete" runat="server" CausesValidation="False" CommandName="Delete" Text="Delete"></asp:LinkButton>
</ItemTemplate>
<FooterTemplate>
<asp:LinkButton ID="ButtonAdd" runat="server" CommandName="Insert" Text="Add to Table" />
</FooterTemplate>
...
Insert Command Codebehind
protected void gvBFMats_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Insert" && Page.IsValid)
{
BFMatsSQL.Insert();
}
}
protected void BFMatsSQL_Inserting
(object sender, ObjectDataSourceMethodEventArgs e)
{
DropDownList ddlNewMfr =
(DropDownList)gvBFMats.FooterRow.FindControl("ddlNewMfr");
DropDownList ddlNewThickness =
(DropDownList)gvBFMats.FooterRow.FindControl("ddlNewThickness");
DropDownList ddlNewCore =
(DropDownList)gvBFMats.FooterRow.FindControl("ddlNewCore");
DropDownList ddlNewSize =
(DropDownList)gvBFMats.FooterRow.FindControl("ddlNewSize");
TextBox txtNewColor =
(TextBox)gvBFMats.FooterRow.FindControl("txtNewColor");
TextBox txtNewQty =
(TextBox)gvBFMats.FooterRow.FindControl("txtNewQty");
DropDownList ddlNewFinish =
(DropDownList)gvBFMats.FooterRow.FindControl("ddlNewFinish");
TextBox txtNewExtra =
(TextBox)gvBFMats.FooterRow.FindControl("txtNewExtra");
// Set the SQLDataSource's InsertParameters values
e.InputParameters["MatManufacturerID"] =
Convert.ToInt32(ddlNewMfr.SelectedValue);
e.InputParameters["MatThicknessID"] =
Convert.ToInt32(ddlNewThickness.SelectedValue);
e.InputParameters["MatCoreID"] =
Convert.ToInt32(ddlNewCore.SelectedValue);
e.InputParameters["MatSizeID"] =
Convert.ToInt32(ddlNewSize.SelectedValue);
e.InputParameters["MatFinishPrePostID"] =
Convert.ToInt32(ddlNewFinish.SelectedValue);
string strNewColor = null;
if (!string.IsNullOrEmpty(txtNewColor.Text))
strNewColor = txtNewColor.Text;
e.InputParameters["MatFinishColor"] = strNewColor;
int? intNewQty = null;
if (!string.IsNullOrEmpty(txtNewQty.Text))
intNewQty = Convert.ToInt32(txtNewQty.Text);
e.InputParameters["MatQty"] = intNewQty;
string strNewExtra = null;
if (!string.IsNullOrEmpty(txtNewExtra.Text))
strNewExtra = txtNewExtra.Text;
e.InputParameters["MatNumExtraSheets"] = strNewExtra;
}
Specifically, I get the red squiggly under the gvBFMats in the (Control)gvBFMats.FooterRow.FindControl("Control ID"); that says "The name 'gvBFMats' does not exist in the current context." I'm only guessing that it doesn't like the call to the GridView when it's nested inside a FormView template. Is there a way to pass this context along programatically?
You're right about it not recognizing the name gvBFMats because it's embedded in a template. Only "top-level", non-embedded controls will be treated in Code Behind as if they had been explicitly declared. Controls declared in a template will not. The compiler doesn't recognize those names.
There's a reason for this. Imagine you have a control called TextBox1 in one of the ItemTemplates for a repeating control. You bind it. Your page's control tree now has dozens of controls with the ID TextBox1. If you want to refer to TextBox1, how does it know which one you mean?
So. What can you do in your situation? Well, BFMatsSQL_Inserting and gvBFMats_RowCommand are both event handlers, so you can't change their signatures.
But, you can make use of them belonging to the same class, and use a module-level variable to hold the reference to gvBFMats. Like this:
private GridView gvBFMats;
protected void gvBFMats_RowCommand(object sender, GridViewCommandEventArgs e)
{
gvBFMats = [your form view].Row.FindControl("gvBFMats") as GridView;
if (e.CommandName == "Insert" && Page.IsValid)
{
BFMatsSQL.Insert();
}
}
Now, BFMatsSQL_Inserting will be able to refer to gvBFMats, and it should have a value.

Manipulating DropDownList within TemplateField

I have a dropdownlist inside of a TemplateField, within a GridView.
I would like to dynamically add list items to it and write code to handle when the index changes. How do I go about manipulating the list, since I can't directly reference the DropDownList when it's in a TemplateField.
Here is my code:
<asp:TemplateField HeaderText="Transfer Location" Visible="false">
<EditItemTemplate>
<asp:DropDownList ID="ddlTransferLocation" runat="server" ></asp:DropDownList>
</EditItemTemplate>
</asp:TemplateField>
If I'm understanding what you want to do correctly, you can handle adding items to your drop down like this:
foreach (GridViewRow currentRow in gvMyGrid.Rows)
{
DropDownList myDropDown = (currentRow.FindControl("ddlTransferLocation") as DropDownList);
if (myDropDown != null)
{
myDropDown.Items.Add(new ListItem("some text", "a value"));
}
}
Then, if you mean handling the index change of the DropDownList you just need to add an event handler to your control:
<asp:DropDownList ID="ddlTransferLocation" runat="server" OnSelectedIndexChanged="ddlTransferLocation_SelectedIndexChanged" AutoPostBack="true"></asp:DropDownList>
Then in that event handler you can use (sender as DropDownList) to get whatever you need from it:
protected void ddlTransferLocation_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList myDropDown = (sender as DropDownList);
if (myDropDown != null) // do something
{
}
}

How can I get the selected value from dropdownlist in edit mode of a gridview?

In my application, when I edit a row in the gridview I choose some new data from a dropdownlist.
I am populating the dropdown like this:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if ((e.Row.RowState & DataControlRowState.Edit) > 0)
{
DropDownList emailsListDL = (DropDownList)e.Row.FindControl("emailsDL");
emailsListDL.DataSource = allUsersEmails;//list of strings with the emails of the users
emailsListDL.DataBind();
}
}
}
But when I press the 'Update' button from the template and enters in the 'RowUpdating' event, the selected value from the dropdownlist is every time the first value from that dropdownlist.
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
DropDownList emailsListDL = (DropDownList)GridViewAdvertisers.Rows[e.RowIndex].FindControl("emailsDL");
string email = emailsListDL.SelectedValue; //the selected value is every time the first value from the dropdownlist
}
Does anyone have any ideas?
I've tried many ways to set the selected value in the 'RowDataBound' event, but with no luck. I tried this:
1. emailsListDL.SelectedIndex = emailsListDL.Items.IndexOf(emailsListDL.Items.FindByValue(DataBinder.Eval(e.Row.DataItem, "OwnerMail").ToString()));
2. emailsListDL.SelectedValue = GridViewAdvertisers.DataKeys[e.Row.RowIndex]["OwnerMail"].ToString();
3. emailsListDL.SelectedValue = GridViewAdvertisers.Rows[e.Row.RowIndex].Cells[1].Text;
//ownerMail is a string (object) from the list of objects that I put as datasource to the gridview
Thanks,
Jeff
Update
My Item template from the aspx page is:
<asp:TemplateField ItemStyle-HorizontalAlign="Center" ItemStyle-VerticalAlign="Middle"
ItemStyle-Width="150px" HeaderText="Owner Email" HeaderStyle-HorizontalAlign="Left"
HeaderStyle-BorderWidth="1px" HeaderStyle-BorderColor="#e1e1e1">
<ItemTemplate>
<asp:Label ID="LabelEmail" runat="server" Text='<%# Bind("OwnerMail")%>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="emailsDL" runat="server" Width="150">
</asp:DropDownList>
</EditItemTemplate>
<HeaderStyle HorizontalAlign="Center" VerticalAlign="Middle" Font-Bold="True"></HeaderStyle>
<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="180px" BorderWidth="1px"
BorderColor="#e1e1e1"></ItemStyle>
</asp:TemplateField>
The SelectedIndex will always default to 0 if you don't define it in your DropDownList definition.
Edit: #Tim Schmelter should add his comment as an anwer. In the meantime, I'll paraphrase for other readers: You need to check for postback (see comments above).
You can declare a ComboBox mainBX = new Combobox();
and you can declare an event
private void onSeletedIndexChange(object sender,EventArgs e)
{
mainBX = (ComboBox)(sender);
}
and next you should iterate foreach ComboBox in GridView and Add this Event .
Than all you should do is ,take the mainBX.seletedItem();
I think this is what you need ,if not apologise .
To set the Selected Value in the RowDataBound-Event, you should do it like this:
(DropDownList)e.Row.Cells[/*index*/].Controls[/*index, or use FindControl*/]).Items.FindByValue(((DataRowView)e.Row.DataItem).Row.ItemArray[/*columnnumber*/].ToString()).Selected = true;
FindByValue finds the current Textvalue of the Field in the "normal" Viewmode and sets the DropDownList with the value.
Of course this needs to be encapsulated in
if ((e.Row.RowState & DataControlRowState.Edit) == DataControlRowState.Edit)
{
}
As for your "getting the Value at Update"-Problem, I must honestly say I've got no clue, since your approach is exactly like mine, only difference: mine works.
Here's my code if it's any help:
protected void gridVariables_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
string control = ((DropDownList)gridVariables.Rows[e.RowIndex].Cells[3].Controls[1]).SelectedValue;
gridVariables.EditIndex = -1;
this.gridVariables_DataBind(control, e.RowIndex);
}
private void gridVariables_DataBind(string control, int index)
{
DataTable dt = (DataTable)Session["variableTable"]; //features a DataTable with the Contents of the Gridview
dt.Rows[index]["ControlType"] = control;
gridVariables.DataSource = dt;
gridVariables.DataBind();
}
I had the same problem with a different solution, I had implemented custom paging on the GridView with a custom pager, and in the process added the RowCommand method, which was rebinding the grid with a new page index. As it happens though the RowCommand method is also called during Updating.
So be sure to check any other locations you may be binding anywhere in your code.
Hope this helps somebody else.
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
string commandName = e.CommandName;
switch (commandName)
{
case "Page1":
HandlePageCommand(e);
//binding should happen here
break;
}
//this line is in the wrong location, causing the bug
BindGrid1();
}

Programmatically access GridView columns and manipulate

I have a GridView :
<asp:GridView ID="GridView1" runat="server" AllowPaging="True" GridLines="None"
HorizontalAlign="Left" AutoGenerateColumns="False"
DataSourceID="SqlDataSource1" onrowcommand="GridView1_RowCommand1">
<HeaderStyle HorizontalAlign="Left" />
<Columns>
<asp:TemplateField HeaderStyle-Width="150">
<HeaderTemplate>
<b>Downloads</b>
</HeaderTemplate>
<ItemTemplate>
<!-- <asp:HyperLink ID="hyperlinkDownload" runat="server" NavigateUrl="" >Download
MP3</asp:HyperLink> -->
<asp:LinkButton CommandName="download"
CommandArgument='<%# Eval("Name") %>' runat="server">Download MP3</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</asp:GridView>
I want to query the value of a particular field in a DB and if it's true, display the LinkButton. if false, I want the linkButton not to be displayed.
is there a way to access the GridView programmatically and make visible certain of its columns or manipulate its items ?
help.
You can do this by adding a handler to the RowDataBound event. Add an event handler along this lines of this in your code behind:
protected void myGrid_RowDataBound(Object sender, GridViewRowEventArgs e)
{
var data = e.Row.DataItem as DataRowView;
if (data != null)
{
var lbtDownload = e.Row.FindControl("lbtDownload");
lbtDownload.Visible = (bool) data.Row["HasFileForDownload"];
}
}
In your markup, attach the event handler to the grid:
<asp:GridView OnRowDataBound="myGrid_RowDataBound" ...>
You will also need to assign an id to the LinkButton, matching the one that you are search for using the FindControl() method in the event handler.
Disclaimer: I am on currently a Linux machine with no chance of testing this. Please report any bugs in the code - feel free to correct them if you have editor rights.
Yes there is.
1) You need to subscribe the RowDataBound event.
2) Give the LinkButton an ID.
3) Insert in codebehind
protected void GridView1_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
LinkButton _bt = e.Row.FindControl("ID") as LinkButton;
if(_bt != null)
{
// have a look at the e.row.DataItem and try to get the value of your desired visibility property
_bt.Visible = true;
}
}
}
4) If this does not work with accessing the DataItem, start thinking about a LinqDataSource.

Categories