Validator controls must always have Display="Dynamic" - c#

i've been working on this for some time now but I can't seem to be able to find the answer... Google doesn't really help me today!
I'm working on an C# website that uses a lot of forms with a lot of validation on it. Big forms which have to be typed by hand, (no problems there though).
The problem that I have is that I always want my ValidationControls to have the Display Property set to dynamic.
I have found a work around but I'm not convinced that this is the best solution.
Currently I have a BaseValidatorControlAdapter that sets the validators display type to "Dynamic" like this:
public class BaseValidatorControlAdapter : ControlAdapter
{
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
System.Web.UI.WebControls.BaseValidator _control = (System.Web.UI.WebControls.BaseValidator)this.Control;
_control.Display = System.Web.UI.WebControls.ValidatorDisplay.Dynamic;
base.Render(writer);
}
}
This is then triggerd by adding an App_Browser which looks like this
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.WebControls.BaseValidator"
adapterType="BaseValidatorControlAdapter" />
</controlAdapters>
</browser>
</browsers>
My question for you is. Is it possible for me to set the default value of Display for any validator control. Because my current solution just overrides what there is right now and there is no way of changing that. Therefor when the situation arrises that I do need something else then dynamic in the display option there is no solution for it.
I'm almost convinced that there is a better solution to this.
Any advice is appreciated!
Edit august 2nd 2012:
I finally settled with the solution to override the default asp.net controls and add the following constructor to them
public controlname ()
: base ()
{
this.Display = "Dynamic";
}
I added all these controls to a namespace and now I can do
<validator:RequiredField ID="RqrdFld_x" runat="server" Display="Static" />
Essentially overriding the default value in my control definition and overriding the default control Display value of Dynamic in the constructor.

This link should be helpful in solving your problem.
You can use a skin file to set defaults for web controls accross a .NET site.
I have added a folder called DefaultTheme to my App_Theme folder and added a file to it called Skin.skin, with the following contents:
<asp:RequiredFieldValidator runat="server" Display="Dynamic" />
<asp:CompareValidator runat="server" Display="Dynamic" />
<asp:RegularExpressionValidator runat="server" Display="Dynamic" />
..allowing me to have a default setting for a number of different validators (or other controls) across my website.

What you can do then use such code in Page_Init event:
foreach(Control control in Page.Controls){
if(control is System.Web.UI.WebControls.BaseValidator)
{
control.Display = "Static";
}
}
It will find all the controls and set the Display property accordingly.

Related

Rendering WebControl with Empty Attribute

Is it possible to build a control that derives from System.Web.UI.WebControls.WebControl that allows 'empty' attributes?
I.e. I need to output <div helloworld></div>
Ive tried overriding RenderEndTag() and this.Attributes.Add("helloworld",null) and neither work correctly.
No. The syntax used for control parsing in ASP.NET web forms requires that attributes must have a value.
The best you could do is to use inner content:
<asp:Label runat="server" id="fooLabel" Text="Hello, world!"/>
is the same as
<asp:Label runat="server" id="fooLabel">Hello, world!</asp:Label>
Looked a bit deeper, the following code works;
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
writer.AddAttribute("helloworld", null);
}
Reflecting System.Web.UI.HtmlTextWriter.RenderBegin() midway down where attributes are written shows the line:
...
this.writer.Write(' ');
this.writer.Write(renderAttribute.name);
if (renderAttribute.value != null)
{
this.writer.Write("=\"");
...
Which shows why the above works, and this.Attributes.Add doesn't (I believe a filter is run to exclude any null attribute values).

Set a property of a custom user control in the code behind

I found this question that shows properties on a custom user control (ascx) can be assigned inline as an HTML attribute: Custom attribute in UserControl (*.ascx)?
This works great but what about if I register a custom user control on my page and want to set/get attributes from that control in my code behind?
ASPX:
<%-- I can assign ActivePage inline and this works fine --%>
<wd:NavBar ID="MyNavBar" runat="server" ActivePage="navbarItem1" />
ASPX.CS:
// I need to change the ActivePage
if (what == "internal")
{
RunInternalComparison();
MyNavBar.ActivePage = "navbarItem1";
}
else if (what == "external")
{
RunExternalComparison();
MyNavBar.ActivePage = "navbarItem2";
}
That's what I want to do but it doesn't work. Is this possible?
Do'h! This actually works. I guess Visual Studio wasn't auto generating controls. Simply adding protected NavBar MyNavBar; to the top of my Page solved the problem. I hope someone else finds this useful.

Server tags cannot contain <% ... %> constructs

I am trying to use CDN for my images on the website.
Problem is, sometimes I have server controls such as ImageButton, and I would like to use a class in order to fully extract the path of the CDN. for that purpose I tried doing:
<asp:ImageButton runat="server" OnClick="Agree" ImageUrl="<%=ResourceManager.GetImageCDN("iagree.png")%>" />
and I get the title as error.
Only if I'm using <%# it will work (and only if I an databinding).
How can I do this easily? how can I place CDN code on my markup code?
Thanks!
There are four options (in addition to "<%# %>" style databinding, which I don't recommend):
Set the value in code behind. This inflates ViewState, and of course requires code changes for every instance of the control.
Use a custom ExpressionBuilder. This doesn't inflate ViewState, but it does require changing all of your markup.
Use a Control Adapter to change the behavior of the control everywhere in your app; for example, by modifying the ImageUrl property before the control is rendered. Can be done with no ViewState impact.
Use a class that inherits from the ImageButton class, combined with tag mapping to use that class instead of the original everywhere in your app, and eliminate the need for changes to your markup. Can be done with no ViewState impact.
The best option depends on your app's requirements, but I usually prefer a control adapter if you want to make the changes site-wide.
Here's an example, in case it helps:
using System;
using System.IO;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.Adapters;
namespace Sample
{
public class ImageButtonControlAdapter : WebControlAdapter
{
protected override void BeginRender(HtmlTextWriter writer)
{
ImageButton image = this.Control as ImageButton;
if ((image != null) && !String.IsNullOrEmpty(image.ImageUrl))
{
//
// Decide here which objects you want to change
//
if (!image.ImageUrl.StartsWith("http") &&
!image.ImageUrl.StartsWith("data:"))
{
image.ImageUrl = ResourceManager.GetImageCDN(image.ImageUrl);
}
}
base.BeginRender(writer);
}
}
}
Configure it into your app with the following entry in App_Browers/adapter.browser:
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.WebControls.ImageButton"
adapterType="Sample.ImageButtonControlAdapter" />
</controlAdapters>
</browser>
</browsers>
Your markup would be:
<asp:ImageButton runat="server" OnClick="Agree" ImageUrl="iagree.png" />
Cool, right??
In case someone else comes across this thread in the future, you can get the required outcome by surrounding the server tag with single quotes, rather than double quotes.
The original:
<asp:ImageButton runat="server" OnClick="Agree" ImageUrl="<%=ResourceManager.GetImageCDN("iagree.png")%>" />
The new version:
<asp:ImageButton runat="server" OnClick="Agree" ImageUrl='<%=ResourceManager.GetImageCDN("iagree.png")%>' />
This works in .Net 4.0, but I would presume that it would work in the other versions too.
You can evaluate code in a server tag by creating your own Code Expression Builder. It's quite simple.
[ExpressionPrefix( "Code" )]
public class CodeExpressionBuilder : ExpressionBuilder
{
public override CodeExpression GetCodeExpression( BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context )
{
return new CodeSnippetExpression( entry.Expression );
}
}
And an entry in your web.config:
<compilation debug="true" targetFramework="4.0">
<expressionBuilders>
<add expressionPrefix="Code" type="[YourNamespace].CodeExpressionBuilder"/>
</expressionBuilders>
</compilation>
This allows you to use a syntax such as:
<asp:ImageButton runat="server" ImageUrl='<%$ Code:ResourceManager.GetImageCDN("iagree.png") %>'>
Here's a full explanation: http://weblogs.asp.net/infinitiesloop/archive/2006/08/09/The-CodeExpressionBuilder.aspx
Of course, your best bet is to give the imagebutton an id, eg:
<asp:ImageButton id="IAgreeImageButton" runat="server" Onclick="Agree" />
And then within your page load assign the imageurl:
void Page_Load(...)
{
if (!Page.IsPostback)
{
IAgreeImageButton.ImageUrl = ResourceManager.GetImageCDN("iagree.png");
}
}

Label not accessible in code view

I did type runat="server" in the label tag. its still not accessible.
I did copy this label from another webform. I've noticed when copying labels from others webforms, sometimes they are not accessible. What is the problem?
Check your designer code and see if its in there. If its not your markup and designer are out of sync unless of course you have the control in a template. I have ran into this issue recently and fixed it by just adding a literal control forcing the designer to regen and then deleting the literal.
from what you have given here, I see you typed runat=server without quotations.
try adding quotations and check again.
runat="server"
full example
<asp:label runat="server" ID="Label1" >Label1</asp:Label>
It's because your code behind class is missing reference to that control. You guess you dont have .designer with your page class, right? Then you have to "map" that control manually
YOu can definie class variable like Label myLabel and then later in Page_Load you have to use myLabel = Find('myLabelId') function, to map that label. (This might not be 100% accurate syntax).
Edit: Asuming your label has ID="Label2", code should look like:
Label _label2;
Page_Load(
// some code
_label2 = (Label)FindControl("Label2");
)

Passing parameters to a User Control

We are trying here to localize our user control basically we want to be able to do something like this :
<in:Banner runat="server" ID="banners" Lang="fr" />
The way we do this is by page level and send it to master that then send it to the control:
protected void Page_Load(object sender, EventArgs e)
{
Master.Lang = "FR";
}
Then in the MasterPage.master we do something like this :
<in:Banner runat="server" ID="banners" Lang="<%= Lang %>" />
The masterpage has a public proprety named Lang.
In the control we have set a field that contains the default language and a proprety (Lang) that set the language. It seems that whatever we do, the current language is not sent from the page to the usercontrol... any help?
Not exactly like that, but you can consider the content page like a control in the master page, so its likely that the page load of the page is executing before the page load of that user control.
Regardless of the above, why not set the ui culture to the asp.net thread (probably from the global.asax), and using that from the control.
Another alternative is to have a separate class where you hold the current language, and expose a change event ... that way you can make sure to use the right language even if the load is done differently --- or there is a change language event later.
You can access it in code-behind of the MasterPage like this
public void SetLanguage(string language)
{
banners.Lang = language; //banners is an ID reference to your user control.
}
Or in your markup I think you can do it like this
<in:Banner runat="server" ID="banners" Lang='<%# Bind("Lang") %>' />
I should mention that Bind works in .Net 2.0 and up.

Categories