Set TemplateField HeaderText dynamic for localization - asp.net

I am trying to create localization for my ASP.NET code, but I have issues setting the TemplateField's HeaderText
I have this that works
<asp:TemplateField HeaderText="Description">
<ItemTemplate>
<%# Eval("Description") %>
</ItemTemplate>
<FooterTemplate>
<asp:Panel ID="Panel5" runat="server" DefaultButton="EditSubmission">
<asp:TextBox runat="server" ID="Submission_DescriptionTxtBox" TextMode="MultiLine"
ToolTip='<%# GetById("atforbedringsforslag_description_tooltip") %>'/>
</asp:Panel>
</FooterTemplate>
</asp:TemplateField>
But I want to change
<asp:TemplateField HeaderText="Description">
To
<asp:TemplateField HeaderText='<%# GetById("atforbedringsforslag_description_title") %>'>
But then I get
Databinding expressions are only supported on objects that have a DataBinding event. System.Web.UI.WebControls.TemplateField does not have a DataBinding event.
How should I set this field? I can find some that uses OnRowCreated, but then you access the fields with an index number, and then it becomes easy to make mistakes or forgot to change indexes if new fields are added later on
EDIT My solution:
Created the custom expression builder
using System.Web.Compilation;
using System;
using System.CodeDom;
public class LocalizationExpressionBuilder : ExpressionBuilder
{
public override CodeExpression GetCodeExpression(System.Web.UI.BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
CodeExpression[] inputParams = new CodeExpression[] { new CodePrimitiveExpression(entry.Expression.Trim()),
new CodeTypeOfExpression(entry.DeclaringType),
new CodePrimitiveExpression(entry.PropertyInfo.Name) };
// Return a CodeMethodInvokeExpression that will invoke the GetRequestedValue method using the specified input parameters
return new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(this.GetType()),
"GetRequestedValue",
inputParams);
}
public static object GetRequestedValue(string key, Type targetType, string propertyName)
{
// If we reach here, no type mismatch - return the value
return GetByText(key);
}
//Place holder until database is build
public static string GetByText(string text)
{
return text;
}
}
Added the prefix to my web.config
<system.web>
<compilation debug="true" defaultLanguage="c#" targetFramework="4.0">
<expressionBuilders>
<add expressionPrefix="localizeByText" type ="LocalizationExpressionBuilder"/>
</expressionBuilders>
</compilation>
</system.web>
And I can now get my text like this
<asp:TemplateField HeaderText='<%$ localizeByText:Some text %>'>

You can build your own custom Expression Builder which calls your GetById method. Look at the following link for an old but good article explaining how to build an expression builder and how to use it:
https://web.archive.org/web/20210304125044/https://www.4guysfromrolla.com/articles/022509-1.aspx
When you have an expression builder, you use it with the <%$ syntax. This is different from the databinding syntax <%#.
For the HeaderText field, it is not allowed to use DataBinding syntax (not sure why, but that's how MS made it). Using expression syntax IS allowed and will work once you have your custom expression builder done.
Do go through the page I linked to, it's quite a lot of text, but in the end making you expression builder will not take much effort...
Also, the page has a link at the bottom to a library of expression builder that the author has made. Have a look at them, maybe one of them could be used directly to solve your problem (specifically, the CodeExpressionBuilder).

Related

Web Forms error message: "This is not scriptlet. Will be output as plain text"

In my ASP .NET Web Forms I have the following declarative code:
<asp:TextBox runat="server" ID="txtbox" CssClass='<%=TEXTBOX_CSS_CLASS%>' />
The constant TEXTBOX_CSS_CLASS is defined in a base class that the page's code-behind class inherits from:
public class MyPageBase : Page
{
protected internal const string TEXTBOX_CSS_CLASS = "myClass";
}
The edit-time compiler however warns me that "This is not scriptlet [sic]. Will output as plain text".
True to its word, the css class is rendered as literally "<%=TEXTBOX_CSS_CLASS%>".
What does this error message mean and is there a workaround so I can still use a constant in a base class?
You cannot use <%= ... %> to set properties of server-side controls.
Inline expressions <% %> can only be used at
aspx page or user control's top document level, but can not be embeded in
server control's tag attribute (such as <asp:Button... Text =<% %> ..>).
If your TextBox is inside a DataBound controls such as GridView, ListView .. you can use: <%# %> syntax. OR you can call explicitly DataBind() on the control from code-behind or inline server script.
<asp:TextBox runat="server" ID="txtbox" class='<%# TEXTBOX_CSS_CLASS %>' />
// code Behind file
protected void Page_Load(object sender, EventArgs e)
{
txtbox.DataBind();
}
ASP.NET includes few built-in expression builders that allows you to extract custom application settings and connection string information from the web.config file. Example:
Resources
ConnectionStrings
AppSettings
So, if you want to retrieve an application setting named className from the <appSettings> portion of the web.config file, you can use the following expression:
<asp:TextBox runat="server" Text="<%$ AppSettings:className %>" />
However, above snippet isn't a standard for reading classnames from Appsettings.
You can build and use either your own Custom ExpressionBuilders or Use code behind as:
txtbox.CssClass = TEXTBOX_CSS_CLASS;
Check this link on building Custom Expression builders.
Once you build your custom Expression you can display value like:
<asp:TextBox Text="<%$ SetValue:SomeParamName %>"
ID="setting"
runat="server" />
The problem is that you can't mix runat=server controls with <%= .. %>code blocks. The correct way would be to use code behind: txtbox.CssClass = TEXTBOX_CSS_CLASS;.
This will work.
Mark up
<asp:TextBox runat="server" ID="txtbox" class='<%# TEXTBOX_CSS_CLASS %>' />
Code-behind
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
txtbox.DataBind();
}
}
But its a lot cleaner to access the CssClass property of the asp:TextBox on Page_Load

ASP.NET string resource to lower case?

I'm including a string resource in an ASPX:
<asp:Literal runat="server" Text="<%$ Resources:Global, MyString %>"/>
Let's say the value of MyString is "Home". How can I convert that to lower case ("home") in the resource tag? E.g., I don't want to have to store both upper/title and lower case variants of the string in the resource file.
I realize I could do this normally (outside a control) like this:
<%= Resources.Global.MyString.ToLower() %>
But that doesn't help when I have to use a resource for some property of a control. I was hoping to be able to do something simple such as:
<asp:Literal runat="server" Text="<%$ (Resources:Global, MyString).ToLower() %>"/>
I ended up building my own ExpressionBuilder which uses the built-in ResourceExpressionBuilder to get the underlying resource value and then convert it to lower case:
Convert the Base Expression to a Lower-case String
public class ResourceLowerCase : ResourceExpressionBuilder
{
public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
CodeExpression getResourceExpression = base.GetCodeExpression(entry, parsedData, context);
CodeMethodInvokeExpression toStringExpression = new CodeMethodInvokeExpression(getResourceExpression, "ToString");
CodeMethodInvokeExpression toLowerExpression = new CodeMethodInvokeExpression(toStringExpression, "ToLower");
return toLowerExpression;
}
}
Register the Expression Builder
<system.web>
<expressionBuilders>
<add expressionPrefix="ResourceLowerCase" type="My.Project.Compilation.ResourceLowerCase"/>
</expressionBuilders>
</compilation>
Invoke the Expression Builder
<asp:Literal runat="server" Text="<%$ ResourceLowerCase:Global, MyString %>" />
Have you tried:
<asp:Literal runat="server" Text="<%$ Code:
GetGlobaloResources("MyString").ToString().ToLower() %>"/>
Just pseudo code.
Update:
http://weblogs.asp.net/infinitiesloop/archive/2006/08/09/The-CodeExpressionBuilder.aspx
Just use the CodeExpressionBuilder from above link.

HTTPContext.Current.User.Identity.Name not working inside a control?

I have a label and I want to set text of this label to
HTTPContext.Current.User.Identity.Name
So I wrote
Text = '<%=HTTPContext.Current.User.Identity.Name %>'
but it doesn't work, however when I wrote this outside of the lable for example:
<h2>
<%=HTTPContext.Current.User.Identity.Name %>
</h2>
it works.
<asp:Label ID="lbUserName"
runat="server"
Text='<%# HttpContext.Current.User.Identity.Name %>'
/>
in Page_Load
if (!Page.IsPostBack )
{
lbUserName.DataBind();
}
use label like this
<asp:label id="lblx" runat="server" ><%= HTTPContext.Current.User.Identity.Name %></asp:label>
To bind the text like this you will have to create your own custom expression builder.
First, add such class to your namespace:
using System.Web.Compilation;
using System.CodeDom;
[ExpressionPrefix("Code")]
public class CodeExpressionBuilder : ExpressionBuilder
{
public override CodeExpression GetCodeExpression(BoundPropertyEntry entry,
object parsedData, ExpressionBuilderContext context)
{
return new CodeSnippetExpression(entry.Expression);
}
}
Next step is adding this to your web.config file:
<compilation debug="true">
<expressionBuilders>
<add expressionPrefix="Code" type="YourNameSpace.CodeExpressionBuilder"/>
</expressionBuilders>
</compilation>
Then finally this should work:
<asp:Label id="YourLabel" runat="server" Text='<%$ Code:HttpContext.Current.User.Identity.Name %>' />
Complicated way to achieve something simple, but this will allow you to use the syntax you want throught your whole project so might worth the extra effort.
Reference.

Using a FormView with LINQ

I am using a FormView control to edit a record fetched using a LinqDataSource. In essence, the markup for the FormView and the data source looks like this:
<asp:FormView ID="RuleInstancePropertiesFormView" runat="server" DataKeyNames="RuleInstanceId"
DataSourceID="RuleInstanceDataSource" DefaultMode="Edit" Visible="false"
CssClass="PropertiesTable">
<EditItemTemplate>
<asp:Label ID="RuleInstanceId" runat="server" Text='<%# Eval("RuleInstanceId") %>' />
<telerik:RadTextBox ID="RuleInstanceNameTextBox"
runat="server"
Text='<%# Bind("Rule.Name") %>' />
<telerik:RadTextBox ID="LimitIndexTextBox"
runat="server"
Text='<%# Bind("LimitIndex") %>' />
</EditItemTemplate>
</asp:FormView>
<asp:LinqDataSource ID="RuleInstanceDataSource" runat="server"
ContextTypeName="Questionnaire.QuestionnairesDataContext"
TableName="RuleInstances" EnableUpdate="true">
</asp:LinqDataSource>
The record I am editing has a foreign key reference to another table, namely the "Rule" table. In the FormView, I need to edit fields in this foreign key table (I have a binding to the Rule.Name field in the above code).
When I try to save my changes, the local field (LimitIndex) is saved correctly in the database, but the foreign field (Rule.Name) isn't. I'm a bit puzzled by this, as the FormView correctly fetches the current value of Rule.Name, but refuses to persist it back to the LINQ object.
I hope anyone can help, thanks :)
You're specifying which table to use as a datasource using the TableName property. This controls which table Linq2Sql will update and so is limiting the update to just the RulesInstances table.
Okay, I found an alternative (but not elegant) solution. I use an ObjectDataSource instead of a LinqDataSource. I have then defined an class
public class RuleInstanceProjection {
public RuleInstanceProjection(){}
// Bind properties from the LINQ object.
public RuleInstanceProjection(RuleInstance instance) { ... }
public int RuleInstanceId {get; set;}
public string Rule_Name {get;set;}
...
}
The object above takes a RuleInstance as constructor, and updates its own properties with all the values that I need in the FormView. I then configure the ObjectDataSource to use another custom class, RuleInstanceProjectionDS, as data source. This class handles updates and inserts of my custom RuleInstanceProjection class:
public class RuleInstanceProjectionDS
{
public RuleInstanceProjectionDS() { }
public RuleInstanceProjection GetRuleInstance(int ruleInstanceId)
{ /* Retrieve the RuleInstance, and instantiate
a RuleInstanceProjection object */ }
public void SaveInstanceProjection(InstanceProjection projection)
{ /* Map fields back to the LINQ objects and submit. */ }
}
I can therefore handle all mappings in these two classes. Now, I only have to decide if this is actually better than updating the GUI controls directly...
I must say it isn't the most elegant solution, and I hope there will be a better data binding framework in later versions of ASP.NET. The current one only seems to handle the most trivial cases :(.

asp.net hyperlnk control

Is it possible to call a class's static property to set the navigateurl property?
<asp:HyperLink ID="hlRegister" NavigateUrl="<%= SomeClass.Property %>" runat="server" />
without using codebehind ofcourse!
You don't need code behind. You can just try it, like i just did. I created a simple page with exactly the code you have, and then created a class called SomeClass with a property named Property. It worked fine for me the way that you have it set up above.
Edit: Ok, it didn't compile with an error.. but It's giving me not the result I'm looking for.
http://localhost:3061/Sample/%3C%=%20SomeClass.Property.ToString()%20%%3E
using:
public static class SomeClass
{
public static string Property
{
get { return "http://www.google.com"; }
}
}
and
<asp:HyperLink ID="hlRegister" NavigateUrl='<%= SomeClass.Property.ToString() %>' Text="Goooooogle" runat="server" />
You can do this, but to avoid a syntax error you must modify your example to be as follows.
<asp:HyperLink ID="hlRegister"
NavigateUrl='<%= SomeClass.Property %>' runat="server" />
Notice the small difference of using single quotes rather than double around the script.
However, one might really ask why not just do it in the codebehind.
sure, in the code behind:
hl.NavigateUrl = Class.Static().ToString();

Resources