ASP.NET Dropdrownlist croaks with SelectValue Assignment - asp.net

This is my aspx
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<asp:ObjectDataSource ID="DSCategories" runat="server"
SelectMethod="GetCategories" TypeName="BAL.CategoryBAL">
</asp:ObjectDataSource>
<div id="Criteria">
<h3>Category:</h3>
<asp:DropDownList ID="ddlCategories" runat="server"
DataSourceID="DSCategories" DataTextField="Description"
DataValueField="Code">
</asp:DropDownList>
<asp:Button ID="btnSetCriteria" runat="server" Text="Set Criteria" />
</div>
</asp:Content>
And this is briefly my Page_Load code:
SearchCriteriaBAL scb = SearchCriteriaBAL.GetSearchCriteria(id);
string cat = String.Empty;
if (!string.IsNullOrEmpty(scb.Criteria))
{
cat = ParseCriteria(scb.Criteria);
ddlCategories.SelectedValue = cat;
}
I break on the SelectedValue assignment line and see the items in the dropdownlist and I see a valid value for cat and it is in the list but I get:
'ddlCategories' has a SelectedValue
which is invalid because it does not
exist in the list of items. Parameter
name: value
It seems to be doing the GetCategories AFTER I set the selectedValue and then it dies.
I placed it on its own test page for fear of interaction but it still fails. Has anyone seen this before?

You could try selecting the item this way:
ddlCategories.Items.FindByValue(cat).Selected = true;
Which of course wont' work if cat really isn't in the Items collection

Write the function on DropDownList's DataBound event instead of Page_Load
Occurs after the server control binds
to a data source.
<asp:DropDownList ID="ddlCategories" runat="server"
DataSourceID="DSCategories"
DataTextField="Description"
DataValueField="Code"
OnDataBound="ddlCategories_DataBound">
</asp:DropDownList>
Rather than using SelectedValue, I would have opted
ddlCategories.Items.FindByValue(cat.Trim()).Selected = true;

Related

Missing something nested in FindControl but always get Null

Literally have read and tried all solutions in Stackoverflow to no avail.
I am trying to get the value of different Dropdownlists genereated from a Repeater and another one just generated on the go, plain and simple.
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
I am trying to get all the selectedValue's of all the dropdownLists genereated thru Repeater and the one that is plain and simply there.
<asp:DropDownList ID="reasonFamily" runat="server">
<asp:ListItem Enabled="true" Text="--------" Value="-1"></asp:ListItem>
<asp:ListItem Text="Option 1" Value="1"></asp:ListItem>
<asp:ListItem Text="Option 2" Value="2"></asp:ListItem>
which looking in the front end, I am getting something like...
<select name="ctl00$ContentPlaceHolder1$reasonFamily" id="ContentPlaceHolder1_reasonFamily">
Which looks good, since I did a button and tried to get this value...
DropDownList ctr = Page.FindControl("Content2").FindControl("reasonFamily") as DropDownList;
TextBox.Text = ctr.SelectedValue;
I could just get the value of reasonFamily.SelectedValue and get finished with... But the problem is, there is another section with a repeater that creates several DropDownList and I need to find all of them and get all their values and Send them to the DB. The DropDownList is all nested in...
<asp:Repeater ID="repStudents" runat="server">
<asp:DropDownList ID="reasonStd" runat="server">
<asp:ListItem Enabled="true" Text="--------" Value="-1"></asp:ListItem>
<asp:ListItem Text="Option 1" Value="1"></asp:ListItem>
<asp:ListItem Text="Option 2" Value="2"></asp:ListItem>
I tried getting finding all of the dropdownlist, but all I get is NULL.
UPDATE: I was able to get the one that is not in the Repeater, but other still eludes me, even tho I have almost tried all the possible choices.
<select name="ctl00$ContentPlaceHolder1$reasonFamily" id="ContentPlaceHolder1_reasonFamily"> // This I was able to access with:
DropDownList ctr = this.Master.FindControl("ContentPlaceHolder1").FindControl("reasonFamily") as DropDownList;
<select name="ctl00$ContentPlaceHolder1$repStudents$ctl01$reasonStd" id="ContentPlaceHolder1_repStudents_reasonStd_1"> //This I could not. Tried all of this:
DropDownList ctr = this.Master.FindControl("ContentPlaceHolder1").FindControl("reasonStd_1") as DropDownList;
DropDownList ctr = this.Master.FindControl("ContentPlaceHolder1").FindControl("repStudents").FindControl("reasonStd_1") as DropDownList;
DropDownList ctr = this.Master.FindControl("ContentPlaceHolder1").FindControl("repStudents")FindControl("reasonStd").FinControl("1") as DropDownList;
Ok, so the 2nd or some other repeater issue - we leave that separate for now.
that last answer SHOWS how we can grab those values - it really the same code.
So, you have a repeater. It has maybe 1 or 15 rows. So, we want to get/grab the drop down list from each row of the repeater.
So, say we have this markup in the repeater (I included your above dropdown list).
So, we have this simple markup:
<asp:Repeater ID="Repeater1" runat="server" >
<ItemTemplate>
<div style="border-style:solid;color:black;width:250px">
<div style="padding:5px;text-align:right">
First Name: <asp:TextBox ID="txtFirst" runat="server" Text ='<%# Eval("FirstName") %>' Width="130px" />
<br />
Last Name: <asp:TextBox ID="txtLast" runat="server" Text ='<%# Eval("LastName") %>' Width="130px" />
<br />
<asp:DropDownList ID="reasonFamily" runat="server">
<asp:ListItem Enabled="true" Text="--------" Value="-1"></asp:ListItem>
<asp:ListItem Text="Option 1" Value="1"></asp:ListItem>
<asp:ListItem Text="Option 2" Value="2"></asp:ListItem>
</asp:DropDownList>
<br />
</div>
</div>
</ItemTemplate>
Ok, now it don't matter if this has 2, or 30 rows. Lets assume it has 3 rows of data. so the above now shows this:
So say when we click on the above button, then we need code (the SAME code in the last question). so the code to process each row, get the values (including the dropdown) could be like this for that button click:
protected void Button1_Click(object sender, EventArgs e)
{
foreach (RepeaterItem rRow in Repeater1.Items)
{
// get First Name.
Debug.Print(rRow.FindControl("txtFirst") as TextBox.Text);
// get LastName
Debug.Print(rRow.FindControl("txtLast") as TextBox.Text);
// get value of drop down box
string strDropDownChoice = rRow.FindControl("reasonFamily") as DropDownList.Text;
Debug.Print("Drop Down option picked = " + strDropDownChoice);
}
}
And output from above loop code would be this:
Output:
Albert
Kallal
Drop Down option picked = 1
Darcy
Caroll
Drop Down option picked = 2
Don
Grant
Drop Down option picked = 2
So, once again, I don't see any real issue or problem with looping over the rows in the data repeater, and then pulling out the values from text box, check box, or a drop down list - it is all quite much the same.

Using c# in Web Forms to passing parameter to user control

From an aspx page, I am trying to display a user control for each item in a collection, but the C# seems to be ignored when tryign to set the UserControl parameter:
<%foreach (Fetus item in this.pregnancy.Fetus) {%>
//this returns a GUID:
"<%= item.Id.ToString() %>"
//this does not work, returns the characters between "" like < %= item.Id.ToString()%>:
<uc1:AntepartumCTGChart runat="server" ID="AntepartumCTGChart" FetusId="<%= item.Id.ToString()%>" />
<% } %>
I would expect this to work, what's wrong?
You have to use a data binding expression
<uc1:AntepartumCTGChart runat="server" ID="AntepartumCTGChart" FetusId='<%# item.Id.ToString()%>' />
But you have to call DataBind() in code behind for that to work.
You can also use a Repeater
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<uc1:AntepartumCTGChart runat="server" ID="AntepartumCTGChart" FetusId='<%# Eval("id").ToString()%>' />
</ItemTemplate>
</asp:Repeater>
And then bind data to it in code behind
Repeater1.DataSource = pregnancy.Fetus;
Repeater1.DataBind();

Passing CommandArguement to LinkButton from variable

I have seen many resources on SO that say that I can use following syntax to pass value to CommandArguement of `LinkButton'
<%forearch(var comment in Comments){%>
<asp:LinkButton ID="del" CommandArguement='<%= comment.CommentId%>' onCommand="delete_click" Text="Delete"/>
<%}%>
But when I write this in my ascx file and click on the link the value passed to command argument is "<%=comment.CommentId%>" instead of commentId itself. Please guide what am I doing wrong?
Edit 1
based on answers and comments, I have moved to use repeater instead of foreach and plain code. Here is the code I have come up with
<asp:Repeater ID="commRepeater" SelectMethod="GetPageComments" runat="server">
<ItemTemplate>
<p>
<%#Eval("Comment") %>
<%if(Page.User.Identity.IsAuthenticated && Page.User.Identity.GetUserId() == Eval("UserId")){ %>
<span>
<asp:LinkButton Text="Edit" runat="server" ID="EditLink" CommandArgument='<%#Eval("CommentId")%>' OnClick="Update_Comment" />
<asp:LinkButton Text="Delete" runat="server" ID="DeleteLink" CommandArgument='<%#Eval("CommentId")%>' OnClientClick="if (!confirm('Are you sure you want delete?')) return false;" OnCommand="Delete_Comment" />
</span>
<%} %>
</p>
</ItemTemplate> </asp:Repeater>
you can see that I am trying to show the edit and delete links if user is logged in and his Id matches with user who commented but it tells me that I can on use Eval in databound controls. how would I hide/show edit/delete links conditionally within repeater
You could simply use codebehind, for example in Page_Load:
protected void Page_Load(Object sender, EventArgs e)
{
if(!IsPostBack)
{
del.CommandArgument = comment.CommentId;
}
}
Maybe a better approach would be to use the Comments-collection(which seems to be a list or array of a custom class) as DataSource of a Repeater(or other web-databound control). Then you can add the LinkButtons to the Itemtemplate.
You can then either use ItemCreated or ItemDataBound events of the repeater in codebehind or inline ASP.NET tags to bind the CommandArgument.
For example:
CommandArguement='<%# DataBinder.Eval( Container.DataItem, "CommentId" ) %>'
What you are doing currently is not recommended and is highly error prone. You can easily achieve this with ASP.NET Repeater control like this:-
<asp:Repeater ID="MyRepeater" runat="server">
<ItemTemplate>
<asp:LinkButton ID="del" CommandArguement='<%# Eval("CommentId") %>'
OnCommand="del_Command" Text="Delete" runat="server" />
</ItemTemplate>
</asp:Repeater>
In Page_Load simply bind it:-
if (!Page.IsPostBack)
{
MyRepeater.DataSource = CommentsRepository();
MyRepeater.DataBind();
}
Or Else if you are have ASP.NET 4.5 then use strongly type Data Bound controls like this:-
<asp:Repeater ID="MyRepeater" runat="server" ItemType="MyNamespace.Comment"
SelectMethod="MyRepeater_GetData">
<ItemTemplate>
<asp:LinkButton ID="del" CommandArguement='<%# Item.CommentId %>'
OnCommand="del_Command" Text="Delete" runat="server" />
</ItemTemplate>
</asp:Repeater>
And you method in code behind should be something like this(just for Demo):-
public IEnumerable<MyNamespace.Comment> MyRepeater_GetData()
{
return new List<Comment>
{
new Comment { CommentId =1, Name= "foo"},
new Comment { CommentId =2, Name= "bar"},
};
}

ASP.NET MultiView with multiple repeaters

I have a problem and I need your opinion. I have a control with a MultiView and each view will be a different render for the control's output, it will be about 10 different views. Inside each view I will have a repeater that will repeat a few rows, this repeater will be the same for all views and since the MultiView only allows 1 view to be show at any one time, I though to have the repeater with the same ID, so I don't have to make 10 bindings and create 10 OnItemDataBound events with the exact same code in it, but ASP.NET don't let me have the repeater with the same ID (it should be smarter than that for this case). I am using C# and v4 of the framework.
Here's the MultiView code:
<asp:MultiView id="MultiView" runat="server">
<asp:View id="h400" runat="server">
<div class="latest_Wide">
<h3>Wide</h3>
<asp:Repeater id="rptLatest" runat="server" OnItemDataBound="rptLatest_OnItemDataBound">
<ItemTemplate>
<p>• <asp:Literal id="litPostTitle1" runat="server" /></p>
</ItemTemplate>
</asp:Repeater>
</div>
</asp:View>
<asp:View id="h200" runat="server">
<div class="latest_Narrow">
<h3>Narrow</h3>
<asp:Repeater id="rptLatest" runat="server" OnItemDataBound="rptLatest_OnItemDataBound">
<ItemTemplate>
<p>• <asp:Literal id="litPostTitle2" runat="server" /></p>
</ItemTemplate>
</asp:Repeater>
</div>
</asp:View>
...
</asp:MultiView>
How can I solve this problem. Remember I don't want to make 10 repeater bindings and have 10 OnItemDataBound events with the exact same code, for the case you suggest to give the repeaters different IDs.
This isn't pretty... but:
Assume your ASCX:
<asp:MultiView id="mvPostDisplay" runat="server">
<asp:View id="h400" runat="server">
<div class="latest_Wide">
<h3>Wide</h3>
<asp:Repeater runat="server" OnItemDataBound="rptLatest_OnItemDataBound">
<ItemTemplate>
<p>• <asp:Literal id="litPostTitle1" runat="server" /></p>
</ItemTemplate>
</asp:Repeater>
</div>
</asp:View>
<asp:View id="h200" runat="server">
<div class="latest_Narrow">
<h3>Narrow</h3>
<asp:Repeater runat="server" OnItemDataBound="rptLatest_OnItemDataBound">
<ItemTemplate>
<p>• <asp:Literal id="litPostTitle2" runat="server" /></p>
</ItemTemplate>
</asp:Repeater>
</div>
</asp:View>
...
</asp:MultiView>
In your codebehind:
private void DataBindRepeater()
{
View activeView = this.mvPostDisplay.GetActiveView();
Repeater myRepeater = this.FindRepeater(activeView);
if (myRepeater != null)
{
myRepeater.DataSource = this.GetDataSourceFormSomewhere();
myRepeater.DataBind();
}
}
private Repeater FindRepeater(Control container)
{
if (container is Repeater)
{
return container as Repeater;
}
else
{
foreach (Control c in container.Controls)
{
Repeater retVal = this.FindRepeater(c);
if (retVal != null)
{
return retVal;
}
}
return null;
}
}
And simply call DataBindRepeater after you've determined the appropriate view. Please note rptLatest will not be set, therefor you will need to get a reference to your repeater in your handler using either the sender, FindRepeater, or possibly something less hackish.
Have you considered making the repeater a user control? This way you have all the repeater binding code once in your user control. Each view will have it's own instance of the usercontrol.
Is this a direction you are willing to take?

RadioButtonList inside UpdatePanel inside Repeater, Can I?

I have a repeater with a RadioButtonList inside the ItemTemplate, but when the RadioButtonList.OnSelectedIndexChanged event fires it generates a full postback. What have I done wrong in my code below? How can I get the OnSelectedIndexChanged to generate an Async Postback?
<asp:UpdatePanel runat="server" ID="UpdatePanel2">
<ContentTemplate>
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="sqlOptions">
<ItemTemplate>
<asp:UpdatePanel runat="server" ID="pnlA">
<ContentTemplate>
<strong>
<%# Eval("Name") %></strong><br />
<asp:RadioButtonList ID="RadioButtonList1"
DataSourceID="sqlOptionValues" runat="server"
DataTextField="id" DataValueField="Id" AutoPostBack="true"
OnSelectedIndexChanged="LoadPrice"
ValidationGroup="options" />
<asp:RequiredFieldValidator ID="RequiredFieldValidator1"
ForeColor="Red" runat="server"
ControlToValidate="RadioButtonList1"
ErrorMessage="Required Field"
ValidationGroup="options" />
<asp:SqlDataSource ID="sqlOptionValues" runat="server"
ConnectionString="<%$ ConnectionStrings:
ConnectionString6 %>"
SelectCommand='<%# "SELECT DISTINCT OptionValue.Name,
OptionValue.Id FROM CombinationDetail
INNER JOIN OptionValue
ON CombinationDetail.OptionValueId = OptionValue.Id
WHERE (OptionValue.OptionId =" +
Eval("Id") + ")" %>'>
</asp:SqlDataSource>
<br />
</ContentTemplate>
</asp:UpdatePanel>
</ItemTemplate>
</asp:Repeater>
</ContentTemplate>
</asp:UpdatePanel>
Many thanks for any help :)
This is a real-world use case. I have a page with Repeaters, Ajax Accordions inside of other Accordions, Update Panels inside other Update panels, you name it. The page works great, except when I want to update one of the Accordion panels with my RadioButtonList (RBL). Even with the RBL inside an update panel, it causes a postback of the entire page. I tried everything. I finally realized it wasn't me when I noticed my buttons would work just fine. I figure it must be a bug in either the framework or the Ajax Control Toolkit. I did find people reference this link all over the web (http://blog.smarx.com/posts/the-case-of-the-radiobuttonlist-half-trigger.aspx), but this link from 2007 is dead now and probably no longer applicable, so that's no help.
What I ended up doing was going with what works - that submit button. All I did was add an onclick attribute to the RBL to call a hidden button. Now you don't want to set the button to Visible=false because then the button won't appear in the generated markup. Instead, set the button's style to display:none; so that no one will see this hack, because yes, that's what this workaround is - it's a hack, but simple and just as effective as what you'd expect. Don't forget to remove the Autopostback="True" from your RBL.
CAVEAT: Because I'm using a hacked button for the onclick event, it's possible for the user to click in the area of the RBL, but not actually select an item. When this happens, our onclick triggers an AsyncPostBack and the codebehind logic will be processed, so please keep that in mind. To give you an idea of what I mean: all the Page_Load() events will be called, but rbl_Questions_SelectedIndexChanged() won't be if they happen to click in the area of the RBL without actually selecting an item. For my purposes this causes no issues in my logic and has no effect on the user.
Here's the Code:
Somewhere In the .Aspx Page:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:RadioButtonList ID="rbl_Questions" runat="server"
OnSelectedIndexChanged="rbl_Questions_SelectedIndexChanged">
</asp:RadioButtonList>
<asp:Button ID="btn_rbl_Questions" runat="server" style="display:none;"/>
<asp:Label ID="lbl_Result" runat="server" Text="" Visible="false">
</asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
In the Page_Load() event:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack == false)
{
//Instead of using the AutoPostback of the RBL, use this instead.
rbl_Questions.Attributes.Add("onclick",
"document.getElementById('"
+ btn_rbl_Questions.ClientID
+ "').click();");
//Bind your RBL to a DataSource, add items programmatically,
// or add them in the aspx markup.
}
}
In the rbl_Questions_SelectedIndexChanged() event:
protected void rbl_Questions_SelectedIndexChanged(object sender, EventArgs e)
{
//Your code here.
//My code unhid the lbl_Result control and set its text value.
}
Update 05/24/2011
The above "hack" is no longer necessary (I am leaving it above since this was marked as the answer by the author). I have found the best way to do this, thanks to this SO Answer:
Updatepanel gives full postback instead of asyncpostback
The code is much simpler now, just remove what I put in the Page_Load() method and remove the Button I used in the Aspx page and add ClientIDMode="AutoID" and AutoPostBack="True" to the control you want the UpdatePanel to capture.
Somewhere In the .Aspx Page:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:RadioButtonList ID="rbl_Questions" runat="server"
ClientIDMode="AutoID" AutoPostBack="true"
OnSelectedIndexChanged="rbl_Questions_SelectedIndexChanged">
</asp:RadioButtonList>
<asp:Label ID="lbl_Result" runat="server" Text="" Visible="false">
</asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
MS changed how ClientID's are generated in .net 4.0 from "AutoID" to "Predictable" and I guess the ScriptManager or UpdatePanel's weren't updated correctly to use it. I can't find documentation on why that is anywhere or if it was left that way by design.
I seriously don't miss winforms.
Try this:
<asp:UpdatePanel runat="server" UpdateMode="Conditional" ID="pnlA">
You'll also need to setup
<Triggers>
//radio buttons
</Triggers>
Not sure how you'll do that since it's a dynamically built list.

Resources