ASP.NET Declarative binding for Hyperlink Visibility not working - c#

I have a hyperlink in a usercontrol that I'd like to set visibility by using a declarative property, i.e.
<asp:HyperLink ImageUrl="/images/icons/rss.png" Visible="<%# ShowRssIcon %>" ID="FeedHyperLink" runat="server"></asp:HyperLink>
However, it always remains visible, even if ShowRssIcon is false. ShowRssIcon is a simple property set on the usercontrol. Even setting ShowRssIcon to always return false results in the hyperlink showing.
However, setting Visible="false" or Visible="true" manually works as expected. Also, setting the property in the code behind on Page_Load event also works.
Any ideas? Thanks.

Since <%# expressions are evaluated at DataBind() time, if you used that, then you need to call DataBind(); method at PreRenderComplete like..
protected void Page_PreRenderComplete(object sender, EventArgs e)
{
DataBind();
}

Your snippet doesn't show any call to DataBind so are you sure there is one? BTW if this hyperlink is not in a databound control like ListView or GridView it is far better to set the property from the code behind.

Related

asp:ListView set SelectMethod with a method having parameter

I have a Listview controls like this
<asp:ListView ID="categoryList" ItemType="CodeCamper.EntityLayer.Transaction.FavoriteVO" DataKeyNames="FavoriteID" GroupItemCount="1" SelectMethod="GetCategories" runat="server">
.....
</asp:ListView>
and in the code behind I'm setting the SelectMethod property
categoryList.SelectMethod = "GetbyTime";
Now if I want to call a parameterized method
public List<FavoriteVO> GetbyTime(string message)
{
...
}
How do I have to modify and assign to categoryList.SelectMethod = section ?
It looks like you want to be able to change the SelectMethod to whatever you want. Because of this, I would remove SelectMethod="GetCategories" from the control declaration and set that in codebehind as well. At least that's where I would start.
Then it will be up to you to set the categoryList.SelectMethod in the proper places in code. e.g. you probably want categoryList.SelectMethod = "GetCategories"; in if (IsPostBack) {} and then categoryList.SelectMethod = "GetbyTime"; within some other event or method, like from a button click or whatnot.
It is VITAL, I repeat VITAL to set EnableViewState="False" on the html declaration of your usercontrol, if you are hosting an asp:ListView inside an ascx control, inside an aspx control!
I wasted days of development time because of this.

Why is ASP.NET submitting the original value of a TextBox control when the contents have been changed?

I have a web form that allows the user to modify data in certain fields (mostly TextBox controls, with a couple of CheckBox, DropDownList, and one RadioButtonList control) with a submit button to save the changes. Pretty standard stuff. The catch is, I need to keep track of which fields they modified. So I'm using ASP.NET HiddenField controls to store the original value and then on submit comparing that to the value of the corresponding TextBox (for example) control to determine which fields have been modified.
However, when I submit the form and do the comparison, the value of the TextBox control in the code behind still reflects the original value, even though I have changed the contents of the TextBox, so it isn't registering the change. Here is an example of a set of TextBox/HiddenField pairings (in this case last, first, middle names) in my ASP.NET form:
<div id="editName" class="editField" style="display: none">
<asp:TextBox ID="tbxLName" runat="server" class="editable"></asp:TextBox>,
<asp:TextBox ID="tbxFName" runat="server" class="editable"></asp:TextBox>
<asp:TextBox ID="tbxMName" runat="server" class="editable"></asp:TextBox>
<asp:HiddenField ID="hdnLName" runat="server" />
<asp:HiddenField ID="hdnFName" runat="server" />
<asp:HiddenField ID="hdnMName" runat="server" />
</div>
I'm setting the original values of all these controls (".Text" for the TextBox controls, ".Value" for the HiddenField controls) on PageLoad in the code behind.
Here's an example of where I'm doing the comparison when I submit the form (I'm adding the field name, old value, and new value to List<string> objects if the values differ):
if (tbxLName.Text != hdnLName.Value)
{
changes.Add("ConsumerLastName");
oldVal.Add(hdnLName.Value);
newVal.Add(tbxLName.Text);
}
But when I enter a new value into the TextBox control and click Submit:
then step through the code in the debugger, it shows me that the value of the control is still the old value:
Why is the comparison happening against the original value of the TextBox even though the new value is there when I click the submit button?
Update: #David gets the credit for this, even though he didn't post it as an answer -- I was forgetting to enclose the method for pre-filling the original values of the controls in a check for IsPostBack; I really should have known better, I've been doing this for quite a while!
Are you checking for IsPostback in Page_Load so you don't overwrite the values sent in the Postback?
Make sure that you are not overwriting your values in the Page_Load method:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
someTextField = "Some Value";
}
}
It took a while for me to get that the Page_Load method works as an "before anything goes" method and not only a method that is being ran when you visit the page with GET.
Make sure you're not overwriting the value for the textbox somewhere in page init or load without checking for the IsPostback flag.
It may happen due to postback. If you code for set textbox not in !isPostBack then put it.
i.e.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
tbxLName.Text="anything";
}
}

GridView OnRowCommand not fired the first time

This probably looks like a duplicate but I don't think so. I have already searched stackoverflow, may be not enough.
Here is my challenge:
<asp:LinkButton runat="server" ID="DeleteRow" CommandName="deleterow"
CommandArgument='<%# Eval("ID") %>' Text="Delete"
OnClientClick="return confirm('Are you sure you want to delete this record?');" />
If you click the link the first time, OnRowCommand is not fired. When you click it the second time, it works.
I looked at the source and I have these differences.
//When you first load the page: the GUID is the PK for that row
1. javascript:__doPostBack('ctl00$content$gvSchoolClasses$58fd1759-f358-442e-bf73-2e9cedfc27e8$DeleteRow','')
//After the link was clicked the first time, the link changed and the ID empty, but works
2. javascript:__doPostBack('ctl00$content$gvSchoolClasses$ctl02$DeleteRow','')
I copied the two codes from the href of the asp:LinkButton for BEFORE and AFTER click.
What is wrong? I only have one other event on my page RowDataBound.
protected void gvSchoolClasses_RowDataBound(object sender, GridViewRowEventArgs e)
{
e.Row.ID = Guid.NewGuid().ToString();
}
protected void Page_Load(object sender, EventArgs e)
{
CheckAuthentication();
if (!Page.IsPostBack)
{
ClassesAcademicYearLabel.Text = "- Year " + Setting.Year;
//FillClassesList(); //filling some combo boxes. Have checked the codes here too
//FillLettersList(); //they didn't affect the Grid
FillGrid();
}
ClassErrorLabel.Visible = false;
}
By setting the ID property of the row in the RowDataBound event, you've created the problem you're observing.
Since the RowDataBound event isn't fired until after the page's controls have already been added to the collection, ASP.NET doesn't have a way to update the already-computed client references. Hence, the command doesn't get fired in the way you're expecting.
I've noticed that you're already setting the CommandArgument property to the ID generated in the RowDataBound event, which could also be part of your problem (depends on order of events firing; I don't have a pipeline chart handy).
EDIT: a quick fix for this could be to simply set the ClientID properties (sorry, not the exact name, but intellisense should get you the rest of the way to it) to some sort of Manual, not Auto determination. That way, the ID you set is never changed by the framework.
To elaborate a bit more on why you're seeing this problem, consider the client-side id's presented:
ctl00$content$gvSchoolClasses$ctl02$DeleteRow
This ID is guaranteed to be unique (for this page) by taking the declared ID (DeleteRow) and successively walking UP the control hierarchy and prepending parent ID's to the string. JS code can be confident that passing this string to getElementById will behave in a consistent, predictable manner.
In order to be able to generate said ID, all of the controls in the hierarchy must already be present and accounted for by the rendering engine.
Now let's consider what happens when that the ID property of a control is changed (note this is not the ClientID, but simply the property with a name of ID).
ctl00$content$gvSchoolClasses$58fd1759-f358-442e-bf73-2e9cedfc27e8$DeleteRow
You'll note that instead of the row's naming container (cl02), it now has the GUID you generated and assigned to it. Client JS attempting to access this container using the previously assigned ID will be disappointed, since it will no longer work as expected!
When an ASP.NET control fires a post-back via a call to javascript:__doPostBack('ctl00$content$gvSchoolClasses$58fd1759-f358-442e-bf73-2e9cedfc27e8$DeleteRow','')
the post-back will occur just fine and dandy, but (and you can verify this by inspecting the form params of the postback) when the server processes the request, it will attempt to rehydrate (from viewstate) a control that doesn't exist. Consequently, it will create a new instance of the control (with the correct ID) which has no idea that a command has been issued, so the XXXCommand event(s) are never fired. Since databinding isn't happening (it's a postback, and your code correctly checks for that condition), the ID is never reset, and the command can be fired normally
don't change the Row.ID in your RowDataBound event. Either change a different value in the grid or just do this in your gridview markup:
CommandArgument='<%: Guid.NewGuid.ToString(); %>'
If you wanted to do it in code behind you could do something like this:
protected void gv_RowDataBound(object sender, GridViewRowEventArgs e)
{
LinkButton deleteRow = (LinkButton)e.Row.FindControl("DeleteRow");
if (deleteRow != null)
deleteRow.CommandArgument = Guid.NewGuid().ToString();
}
You need to set the Row Index to the CommandArgument of the Link Button not the guid
As you said it work in the second time but the html is as shown below
//After the link was clicked the first time, the link changed and the ID empty, but works
2. javascript:__doPostBack('ctl00$content$gvSchoolClasses$ctl02$DeleteRow','')

DateTime.Now.Year to fill maximum value in RangeValidator

I am using a RangeValidator to validate that a year is between a static start year and a dynamic end year (the current year). I am drawing a huge blank for setting the maximum value in this fashion:
MaximumValue='<% DateTime.Now.Year %>'
Any help is appreciated as I usually don't set max values in this fashion.
Edit:
So I have been given the following ways to incorporate the code into the codebehind:
validator init event
page prerender
and i'm a newb and would just have done on page load
which is best?
By default, ASP.NET doesn't let you do this; the <%= ... %> syntax doesn't work either.
The easiest way is to just set the MaximumValue property in the code-behind, in the validator's Init event. (This is better than the page's Init, Load, or PreRender event, which would bloat view state.)
protected void rangeValidator_Init(object sender, EventArgs e)
{
((RangeValidator)sender).MaximumValue = DateTime.Now.Year.ToString();
}
By using the sender parameter, multiple RangeValidator controls on the page can all share this event handler.
If you really wanted to set the MaximumValue in the .ascx/.aspx, then take a look at this blog post: The CodeExpressionBuilder.
UPDATE: Setting MaximumValue in Init, Load, and PreRender would all work. Init has the slight advantage that it avoids increasing the size of view state. PreRender has the additional disadvantage that server-side validation would break if view state were disabled for the validator.
It works without codebehind
<asp:RangeValidator ID="RangeValidator1" runat="server"
ControlToValidate="TextBox2" ErrorMessage="RangeValidator"
MaximumValue='<%# DateTime.Now.Year %>' MinimumValue="2000"></asp:RangeValidator>
and call this method in the page load event
DataBind();
you can try like this by code behind , check for Range validator documentaion RangeValidator
aspx markup
<asp:RangeValidator ID="MaxDate" runat="server" ErrorMessage="Some Error message" ControlToValidate="SomeControltoValidate"
Display="Dynamic" Type="Date" ></asp:RangeValidator >
code behind file. for page pre-render event.
protected void Page_PreRender(object sender, EventArgs e)
{
MaxDate.MaximumValue = DateTime.Now.Date.AddYears(1).ToString("MM/dd/yyyy");
}
You need an = to cause the evaluated value to be returned by the <% %>.
MaximumValue='<%= DateTime.Now.Year %>'
Changing from using DateTime.Now to DateTime.Today
RangeVal.MinimumValue = DateTime.Today.ToShortDateString();
RangeVal.MaximumValue = DateTime.Today.AddYears(50).ToShortDateString();

Postback events from within DataView

I'm presenting information from a DataTable on my page and would like to add some sorting functionality which goes a bit beyond a straight forward column sort. As such I have been trying to place LinkButtons in the HeaderItems of my GridView which post-back to functions that change session information before reloading the page.
Clicking my links DOES cause a post-back but they don't seem to generate any OnClick events as my OnClick functions don't get executed. I have AutoEventWireup set to true and if I move the links out of the GridView they work fine.
I've got around the problem by creating regular anchors, appending queries to their hrefs and checking for them at page load but I'd prefer C# to be doing the grunt work. Any ideas?
Update: To clarify the IDs of the controls match their OnClick function names.
You're on the right track but try working with the Command Name/Argument of the LinkButton. Try something like this:
In the HeaderTemplate of the the TemplateField, add a LinkButton and set the CommandName and CommandArgument
<HeaderTemplate>
<asp:LinkButton ID="LinkButton1" runat="server" CommandName="sort" CommandArgument="Products" Text="<%# Bind('ProductName")' />
</HeaderTemplate>
Next, set the RowCommand event of the GridView
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "sort")
{
//Now sort by e.CommandArgument
}
}
This way, you have a lot of control of your LinkButtons and you don't need to do much work to keep track of them.
Two things to keep in mind when using events on dynamically generated controls in ASP.Net:
Firstly, the controls should ideally be created in the Page.Init event handler. This is to ensure that the controls have already been created before the event handling code is ran.
Secondly, you must assign the same value to the controls ID property, so that the event handler code knows that that was the control that should handle the event.
You can specify the method to call when the link is clicked.
<HeaderTemplate>
<asp:LinkButton
ID="lnkHdr1"
Text="Hdr1"
OnCommand="lnkHdr1_OnCommand"
CommandArgument="Hdr1"
runat="server"></asp:LinkButton>
</HeaderTemplate>
The code-behind:
protected void lnkHdr1_OnCommand(object sender, CommandEventArgs e)
{
// e.CommandArgument
}

Categories