Is there any way to declaratively pass code-behind property values to server controls? - asp.net

Can anyone explain why you can’t use inline code blocks within server control declarations in ASP.Net?
The following is a simple example...
....
<form id="form1" runat="server">
<asp:Label ID="Label1" runat="server" Text="<%= SomeProperty %>"></asp:Label>
</form>
....
The code block is rendered literally to the page...
<span id="Label1"><%= SomeProperty %></span>
My initial thoughts are it has to do with the order that these things are processed in the page life-cycle. The <%=...%> blocks are, as I understand it, equivalent to a Response.Write(...) in code-behind. And since the server control is not actually rendered as declared in the markup, I suppose it may not be possible to process an embedded code block before this rendering takes place.
I would be very grateful of anyone could explain that a little better.
However, the data binding code block <%#...%> is obviously different in the way it behaves, but can anyone tell me why it is possible to embed these within a server control...
....
<asp:Repeater id=Repeater1 runat="server">
....
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Eval(“SomeProperty”) %>'></asp:Label>
</ItemTemplate>
....
</asp:Repeater>
....
This works fine.

You're mostly right about the <%=...%> syntax.
Here is an example of what happens under the hood:
<script runat="server">
public string SomeProperty { get { return "Hello World!"; } }
</script>
<form id="form1" runat="server">
<%= SomeProperty %>
<div>
<asp:Label ID="Label1" runat="server" Text="<%= SomeProperty %>"></asp:Label>
</div>
</form>
This is parsed and the following C# code is created (I've simplified it a bit):
private Label #__BuildControlLabel1()
{
Label #__ctrl = new Label();
this.Label1 = #__ctrl;
#__ctrl.ApplyStyleSheetSkin(this);
#__ctrl.ID = "Label1";
#__ctrl.Text = "<%= SomeProperty %>";
return #__ctrl;
}
private void #__Renderform1(HtmlTextWriter #__w, Control parameterContainer)
{
#__w.Write( SomeProperty );
#__w.Write("\r\n <div>\r\n ");
parameterContainer.Controls[0].RenderControl(#__w);
#__w.Write("\r\n </div>\r\n ");
}
Here is an example of what happens under the hood for the <%#...%> syntax:
<script runat="server">
public string SomeProperty { get { return "Hello World!"; } }
protected void Page_Load(object sender, EventArgs e) { Label1.DataBind(); }
</script>
<form id="form1" runat="server">
<div>
<asp:Label ID="Label1" runat="server" Text="<%# SomeProperty %>"></asp:Label>
</div>
</form>
Generates this code:
private Label #__BuildControlLabel1()
{
Label #__ctrl = new Label();
this.Label1 = #__ctrl;
#__ctrl.ApplyStyleSheetSkin(this);
#__ctrl.ID = "Label1";
#__ctrl.DataBinding += new System.EventHandler(this.#__DataBindingLabel1);
return #__ctrl;
}
public void #__DataBindingLabel1(object sender, EventArgs e)
{
Label dataBindingExpressionBuilderTarget = ((Label)(sender));
Page Container = ((Page)(dataBindingExpressionBuilderTarget.BindingContainer));
dataBindingExpressionBuilderTarget.Text = System.Convert.ToString( SomeProperty , System.Globalization.CultureInfo.CurrentCulture);
}
As you can see the <%=...%> syntax can be used outside of a server control's properties to directly render the returned value. On the other hand the <%#...%> syntax generates a event handler for the DataBinding event of the label. This event sets the value of the label's property to the value of SomeProperty. The DataBinding event fires whenever the DataBind method is called which is why I added that call to the Page_Load event.
Hopefully this will help you understand the difference between them.

You could create a custom ExpressionBuilder so you use something like <%$ Code: SomeProperty %>

You can create a custom databound control, e.g.
namespace FooBar.WebControls
{
public class DataBoundPlaceHolder:PlaceHolder
{
private bool hasDataBound = false;
protected override void CreateChildControls()
{
if (!hasDataBound)
{
this.DataBind();
hasDataBound = true;
}
base.CreateChildControls();
}
}
}
Then wrap your code in this new control, and use the <%# %> syntax, e.g.
<%# Register TagPrefix="WebControls" Namespace="FooBar.WebControls" Assembly="FooBar" %>
<form id="form1" runat="server">
<WebControls:DataBoundPlaceHolder runat="server">
<asp:Label ID="Label1" runat="server" Text='<%# SomeProperty %>'></asp:Label>
</WebControls:DataBoundPlaceHolder>
</form>

Related

Radio button to select one box only....ERROR

Something is wrong with the following code cause I can select more than one radiobutton at the same time.... How can I make the following code select only one radiobutton? Please help.
<asp:ListView ID="ListView1" runat="server" DataSourceID="SqlDataSource_BGlist">
<ItemTemplate>
<asp:RadioButton ID="Radio1" GroupName="BG_name" runat="server" Text='<%# Eval("BG_fileName") %>' />
<asp:Label ID="BG_fileNameLabel" runat="server" Text='<%# Eval("BG_fileName") %>' />
</ItemTemplate>
</asp:ListView>
The easiest way to accomplish this is to just wrap your listview in an ASP.NET Panel or GroupBox, and ASP will implement the grouping you want.
Adding a panel doesn't group radio buttons together if they are contained in some sort of repeater. Probably the best solution is to use a RadioButtonList as suggested in Grebets' Answer.
If that doesn't suit your needs you can use javascript to alter the radio buttons after they have been created. The following code will work when added to the bottom of your page:
<script type="text/javascript">
var inputElements = document.getElementsByTagName("input");
for (var inputName in inputElements) {
var input = inputElements[inputName];
if (input.type === "radio") {
input.name = "Group1";
}
}
</script>
The script can be simplified if you are using jQuery.
I think the most effective way will be use RadioButtonList:
<asp:RadioButtonList ID="RadioButtonList1" runat="server" DataTextField="BG_fileName" DataValueField="BG_fileName" DataSourceID="SqlDataSource_BGlist">
</asp:RadioButtonList>
And if you preffer to use datasources in codebehind (like I do):
public class MyClass
{
public string BG_fileName { get; set; }
public MyClass(string bgFileName)
{
BG_fileName = bgFileName;
}
}
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
RadioButtonList1.DataSource = new List<MyClass>
{
new MyClass("test string 1"),
new MyClass("test string 2"),
new MyClass("test string 3")
};
RadioButtonList1.DataBind();
}
}

I want to get property value from code behind

I have a case that I need to set the Text property for an asp label in the aspx page not from code behind. More exactly, I need to set a value to asp control in aspx page and this value is set by a property in the same page code behind.
so I need to use an expression to do that like:
<asp:Label Text="<%= MyProperty %>" ..../>
I use:
<%= MyProperty %> doesn't work.
<%# MyProperty %> doesn't also.
Default.aspx.cs
public partial class _Default : System.Web.UI.Page
{
public string CustomTitle = "This Is Title";
protected void Page_Load(object sender, EventArgs e)
{
Page.DataBind();
}
}
Default.aspx
<asp:Label Text='<%#CustomTitle %>' runat="server" />
You have to treat regular HTML and WebControls differently:
regular HTML:
Using <%= ... %> is sufficient:
<span><%= MyProperty %></span>
WebControls (stuff starting with <asp:...>):
<asp:Label Text='<%# MyProperty %>' />
In this case, you also have to call Me.DataBind() (VB) or this.DataBind(); (C#) in your codebehind, since <%# ... %> are data binding expressions.
Page.DataBind();
Do you call this in your code? It binds all variables set in code to your page.

Required field validator for multiple dropdown lists in an aspx page

I have an aspx page which has 18 (yes 18) dropdown lists and 18 text boxes. Each dropdown needs to be selected and each textbox needs to be filled. Dragging and dropping required field validators on these 36 controls and maintaining them is a painful task and does not seem to be the logical option as all I need is for the user to select a value from the dropdown.
Is there anyway I can loop through all these dropdown controls and textbox controls, check if they are empty and display warnings to users accordingly? Client-side validation solution or server side validation solution is fine with me.
Use a CustomValidator and have a client script function that makes sure every text box/drop down has a value.
One suggestion is to loop through all the controls on the page, use recursive function to dynamically bind RequiredFieldValidator to the found controls. You can tweak my code to suit your needs.
This code has some drawbacks though:
Use control.ID instead of associated label text
Adding RequiredFieldValidator to the page.controls will modify its ControlCollection. This will break the foreach method. Thus, I can only add RequiredFieldValidator to Panel instead.
.aspx
<asp:Panel ID="pnlValidation" runat="server">
</asp:Panel>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
<asp:TextBox ID="TextBox3" runat="server"></asp:TextBox>
<br />
<asp:DropDownList ID="DropDownList1" runat="server" />
<asp:DropDownList ID="DropDownList2" runat="server" />
<asp:DropDownList ID="DropDownList3" runat="server" />
<br />
<asp:Button ID="Button1" runat="server" Text="Button" />
.cs
protected void Page_Load(object sender, EventArgs e)
{
AddValidator(this);
}
private void AddValidator(Control ctrl)
{
if (ctrl is TextBox || ctrl is DropDownList)
{
RequiredFieldValidator rfv = new RequiredFieldValidator();
rfv.ControlToValidate = ctrl.ID;
rfv.Display = ValidatorDisplay.Dynamic;
rfv.ErrorMessage = ctrl.ID + " is required<br />";
pnlValidation.Controls.Add(rfv);
}
foreach (Control subctrl in ctrl.Controls)
AddValidator(subctrl);
}
If you are dynamically generating the textboxes and dropdownlists, you would probably want to dynamically generate the validation controls as well, but if all the drop down lists and textboxes are static you can use the following:
Use a CustomValidator Web Control, write client side javascript method that checks all the properties of the drop down lists and the textboxes and configure the web control's ClientValidationFunction with the function and set EnableClientScript=true. Also, b/c not all users have javascript enabled, plus to be sure as it is best practice, always also create a server side validation function as well and call Page.IsValid() on the submit action.
.aspx Sample Code
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs"
Inherits="Default2" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script language="javascript" type="text/javascript">
function ValidateMe(sender, args) {
var txt = document.getElementById("txt");
if (txt.value != "")
args.IsValid = true;
else
args.IsValid = false;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:TextBox id="txt" runat="server" />
<asp:CustomValidator ClientValidationFunction="ValidateMe" ID="custval"
runat="server" ErrorMessage="Fail" onservervalidate="custval_ServerValidate" />
<asp:Button ID="btn" runat="server" Text="push" onclick="btn_Click1" />
</form>
</body>
</html>
c# codebehind sample code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Globalization;
using System.Threading;
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
}
}
protected void btn_Click1(object sender, EventArgs e)
{
if (Page.IsValid)
{
btn.Text = "PASS";
}
else
{
btn.Text = "FAIL";
}
}
protected void custval_ServerValidate(object source, ServerValidateEventArgs args)
{
if (txt.Text != "")
custval.IsValid = true;
else
custval.IsValid = false;
}
}

Public Properties in Code Behind of a User Control

In a regular .aspx page, you can access public properties from the codebehind. Is there any way to do a similar thing in a user control. For example, in the following code 'List' is public property of the codebehind of the user control and yet it is not accessible.
<% foreach (TripTeam team in List) { %>
<div>
<label><%= team.Name %></label>
</div>
<%} %>
You can access the public properties of a UserControl from your .aspx page. Here's an example
<script runat="server">
public string Caption { get { return _caption.Text; } set { _caption.Text = value; } }
public string Text{ get { return _tb1.Text; } set { _tb1.Text = value; } }
<div>
<asp:Label ID="_caption" runat= "server" class="caption" /><br />
<asp:TextBox ID="_tb1" runat="server" CssClass="textBox" Width="25px" />
Then on your aspx page, you can set the Text and Caption properties within your user control:
<uc1:CaptionText ID="ct1" runat="server" Caption="User name" />
You need to say 'userControlId.List' to access the property when accessing a property in the control from a page which uses the control.

ASP.NET - Control Events Not Firing Inside Repeater

This is a absurdly common issue and having exhausted all of the obvious solutions, I'm hoping SO can offer me some input... I have a UserControl inside a page which contains a repeater housing several controls that cause postback. Trouble is, all of the controls inside of the repeater never hit their event handlers when they postback, but controls outside of the repeater (still in the UC) are correctly handled. I already made sure my controls weren't being regenerated due to a missing if(!IsPostBack) and I verified that Request.Form["__EVENTTARGET"] contained the correct control ID in the Page_Load event. I attempted to reproduce the symptoms in a separate project and it worked as it should.
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="NoteListControl.ascx.cs"
Inherits="SantekGBS.Web.UserControls.NoteListControl" %>
<asp:UpdatePanel ID="upNotes" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<div class="NoteList" id="divNoteList" runat="server">
<asp:Repeater ID="repNotes" runat="server">
<HeaderTemplate>
<table width="98%" cellpadding="3" cellspacing="0">
</HeaderTemplate>
<ItemTemplate>
<tr class="repeaterItemRow">
<asp:ImageButton ID="ImageButton1" runat="server" ImageUrl="~/Content/images/DeleteIcon.gif"
OnClick="ibRemove_Click" CommandArgument='<%# Container.ItemIndex %>' CommandName='<%# Eval("ID") %>'
CausesValidation="false" AlternateText="Delete" />
<%# Eval("Text") %></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
<asp:PlaceHolder ID="phNoNotes" runat="server" Visible="false">
<div class="statusMesssage">
No notes to display.
</div>
</asp:PlaceHolder>
</div>
</ContentTemplate>
</asp:UpdatePanel>
public partial class NoteListControl : UserControl
{
[Ninject.Inject]
public IUserManager UserManager { get; set; }
protected List<Note> Notes
{
get
{
if (ViewState["NoteList"] != null)
return (List<Note>)ViewState["NoteList"];
return null;
}
set { ViewState["NoteList"] = value; }
}
public event EventHandler<NoteEventArgs> NoteAdded;
public event EventHandler<NoteEventArgs> NoteDeleted;
public event EventHandler<NoteEventArgs> NoteChanged;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
UtilityManager.FillPriorityListControl(ddlPriority, false);
}
}
protected void ibRemove_Click(object sender, ImageClickEventArgs e)
{
System.Diagnostics.Debug.WriteLine("ibRemove POSTBACK"); // This is NEVER hit
}
public void Fill(List<Note> notes)
{
Notes = notes;
RefreshRepeater();
}
private void RefreshRepeater()
{
if (Notes != null && Notes.Any())
{
var sorted = Notes.OrderByDescending(n => n.Timestamp);
Notes = new List<Note>();
Notes.AddRange(sorted);
repNotes.Visible = true;
phNoNotes.Visible = false;
repNotes.DataSource = Notes;
repNotes.DataBind();
}
else
{
repNotes.Visible = false;
phNoNotes.Visible = true;
}
}
}
public class NoteEventArgs : EventArgs
{
public Note Note { get; set; }
public NoteEventArgs()
{ }
public NoteEventArgs(Note note)
{
this.Note = note;
}
}
The code is intentionally missing functionality so just disregard that fact.
Your edited code has residual CommandArgument and CommandName properties; are you actually handling the Repeater.ItemCommand event?
If so, and if your page calls the control's Fill method on postbacks, that would explain it.
This classic ASP.NET hair-tearing problem is explained in these posts: A Stumper of an ASP.NET Question and A Stumper of an ASP.NET Question: SOLVED!
The explanation is a little mind-bending, but the crux of it is that Repeater.DataBind interferes with ASP.NET's ability to determine which repeater button caused a postback.
I found a missing td-tag in the Itemtemplate, sometimes when DOM is incorrect, the updatapanel do strange things.
Just about EVERY time I run into this problem it's because DataBind() is being called when it shouldn't be. This will kill most events from controls inside a repeater. I see you have an !IsPostBack check in your Page_Load... so that's a start. But try putting a breakpoint on repNotes.DataBind() and see if it's getting called when you don't expect it.
Does it work OK outside of an UpdatePanel?
I ran into the same problem. It happened with me if I've ran the DataBind twice. In other words when I populate the repeater control twice (for any reason) the events wont fire.
I hope that helps.

Resources