User Control with Input Parameter - asp.net

I have a user control with property (*.acsx.cs):
public partial class controls_PersonAccessStatus : System.Web.UI.UserControl
{
public Person Person { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
}
}
Is there some way to pass parameter to this control in *.aspx, something like this
<% foreach (Person p in persons) { %>
<uc:PersonAccessStatus ID="PersonAccessStatus" runat="server" Person=p />
<% } %>

Yes. You can create a property on the UserControl. I typically use it to enable or disable functions of a control. It is simple to assign a value in the aspx.
<uc:PersonAccessStatus ID="PersonAccessStatus" runat="server" EnableSomething="true" />
I am not sure about the syntax for your example as I usually keep code out of the aspx, so I would do the looping in the code.
foreach (Person p in persons)
{
control = LoadControl("~/App_Controls/PersonAccessStatus.ascx")
as PersonAccessStatus;
control.Person = p;
SomeContainer.Controls.Add(control);
}

Thank you g. You really helped me although I have not found more elegant solution. From *.aspx side it looks so:
<%foreach (Person p in persons)
{
controls_PersonAccessStatus control = LoadControl("~/App_Controls/PersonAccessStatus.ascx") as controls_PersonAccessStatus;
control.Person = p; %>
<%=RenderControl(control) %>
<%}%>
Where RenderControl ia a helper function:
public string RenderControl(Control ctrl)
{
StringBuilder sb = new StringBuilder();
StringWriter tw = new StringWriter(sb);
HtmlTextWriter hw = new HtmlTextWriter(tw);
ctrl.RenderControl(hw);
return sb.ToString();
}

All of the parameter and functions must be declared with <%= this.ID %> in the asp user control to use it more than one time.
For example:
var ii<%= this.ID %> = 0;
or
function load_2v<%= this.ID %> ()
{
var BI1 = document.getElementById("<%= Li1.ClientID %>");
var BI2 = document.getElementById("<%= Li2.ClientID %>");
switch (ii<%= this.ID %>) {

Related

Binding data to html5 DataList in asp.net

I'm trying my hands with HTML5. Is it possible to bind data to datalist in html5 as we bind data from a datatable to asp.net dropdown control.
Where i can find this details. any pointers is much appreciated. :)
Thanks
1) Assign runat="server" to the datalist so that it can be accessed from code behind:
Enter your favorite browser name:<br />
<input id="browserName" list="browsers" />
<datalist id="browsers" runat="server" />
2) Loop through the DataTable, construct and concatenate a list of options using a StringBuilder and add the result to the InnerHtml property of the datalist
protected void Page_Load(object sender, EventArgs e)
{
DataTable table = new DataTable();
table.Columns.Add("BrowserName");
table.Rows.Add("IE");
table.Rows.Add("Chrome");
table.Rows.Add("Firefox");
table.Rows.Add("Opera");
table.Rows.Add("Safari");
var builder = new System.Text.StringBuilder();
for (int i = 0; i < table.Rows.Count; i++)
builder.Append(String.Format("<option value='{0}'>",table.Rows[i][0]));
browsers.InnerHtml = builder.ToString();
}
If you're going to need this functionality in multiple places in your site, you can either create a WCF service and call it via jQuery where you can populate the datalist or create an HTTP handler like this:
1)Add a Generic Handler to your project and call it AutoCompleteHandler.ashx
2)Inside AutoCompleteHandler.ashx put:
public class AutoCompleteHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Clear();
var options = new System.Text.StringBuilder();
options.Append("<option value='IE'>");
options.Append("<option value='Chrome'>");
options.Append("<option value='Firefox'>");
options.Append("<option value='Safari'>");
options.Append("<option value='Opera'>");
context.Response.Write(options.ToString());
context.Response.End();
}
public bool IsReusable
{
get{return false;}
}
}
3)Call the handler via jQuery when the page loads and populate the datalist with the returned result:
<script src="Scripts/jquery-1.9.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$.post('AutoCompleteHandler.ashx', function (data) {
$('#browsers').html(data);
});
});
</script>

How can I programmatically build a System.Web.UI.Page with a Form and a UserControl?

I have this code:
public static string RenderView(string path)
{
Page pageHolder = new Page();
UserControl viewControl = (UserControl)pageHolder.LoadControl(path);
pageHolder.Controls.Add(viewControl);
StringWriter output = new StringWriter();
HttpContext.Current.Server.Execute(pageHolder, output, false);
return output.ToString();
}
Which is run from:
[WebMethod]
public string GetReportsHTML()
{
string output = "";
output = ViewManager.RenderView("ReportsControl.ascx");
return output;
}
This is to test rendering ASCX files and spitting them out of a SOAP/REST service.
Problem is, some controls (runat=server ones) fail if they are not encapsulated in a tag with runat=server.
The solution to that is here, but the solution assumes being inside an ASPX file where I can just edit the markup.
How would I programmatically build a Page, add a Form, set runat=server so that I can follow that solution and add my control to the Form Control?
Have you tried something like this ?
public static string RenderView(string path)
{
Page pageHolder = new Page();
System.Web.UI.HtmlControls.HtmlForm formHolder = new System.Web.UI.HtmlControls.HtmlForm();
pageHolder.Controls.Add(formHolder );
UserControl viewControl = (UserControl)pageHolder.LoadControl(path);
formHolder.Controls.Add(viewControl);
StringWriter output = new StringWriter();
HttpContext.Current.Server.Execute(pageHolder, output, false);
return output.ToString();
}
Hope this will help

OnCheckedChanged Nested Listview Controls

I have the following nested listview...
<asp:ListView ID="lvwRiskQuestions" runat="server" ItemPlaceholderID="QuestionItemPlaceholder">
<LayoutTemplate>
<asp:PlaceHolder ID="QuestionItemPlaceholder" runat="server" />
</LayoutTemplate>
<ItemTemplate>
<%# Eval("DESCRIPTION")%>
<asp:ListView ID="lvwAnswers" runat="server" ItemPlaceholderID="AnswerItemPlaceholder" DataSource='<%# Eval("Answers")%>'>
<LayoutTemplate>
<asp:PlaceHolder ID="AnswerItemPlaceholder" runat="server" />
</LayoutTemplate>
<ItemTemplate>
<asp:RadioButton ID="rdbSelect" runat="server" AutoPostBack="true" OnCheckedChanged="rdbSelectChanged"/>
<%# Eval("Description")%>
</ItemTemplate>
</asp:ListView>
</ItemTemplate>
</asp:ListView>
I get hold of the radio buttons OnCheckedChanged like so...
Protected Sub rdbSelectChanged(ByVal sender As Object, ByVal e As System.EventArgs)
Dim rb1 As RadioButton = CType(sender, RadioButton)
Dim lvwAnswers = DirectCast(lvwRiskQuestions.FindControl("lvwAnswers"), ListView)
For Each row As ListViewItem In lvwAnswers.Items
Dim rb As RadioButton = row.FindControl("rdbSelect")
If rb IsNot Nothing AndAlso rb.Checked Then
rb.Checked = False
End If
Next
rb1.Checked = True
End Sub
The problem i have is 'lvwAnswers' is Nothing. I'm guessing im not doing my findcontrol correctly.
Any help greatly appreciated.
If you're just generating a list of radio-buttons for the answers, you could use the RadioButtonList control. This would generate the correct HTML so that only one answer could be selected per question without having to post-back to de-select the other options.
If your answer template contains more than a single RadioButton, things get more complicated. When it's not hosted in a RadioButtonList, the RadioButton uses the UniqueID of the parent NamingContainer to build its unique group name. Unfortunately, in your example, the NamingContainer will be the ListViewDataItem from the lvwAnswers list, and each answer will have a different ID.
What you need is a RadioButton which will look at the NamingContainer's NamingContainer to generate its group name. You could either re-implement the RadioButton control, or use a little bit of reflection to update the private _uniqueGroupName field:
[ToolboxData("<{0}:ListRadioButton runat=\"server\" />")]
public class ListRadioButton : RadioButton
{
private static readonly FieldInfo UniqueGroupNameField = FindUniqueGroupNameField();
private string _uniqueGroupName;
private static FieldInfo FindUniqueGroupNameField()
{
return typeof(RadioButton).GetField("_uniqueGroupName",
BindingFlags.NonPublic | BindingFlags.Instance);
}
protected virtual string CreateUniqueGroupName()
{
string result = GroupName;
if (string.IsNullOrEmpty(result))
{
result = ID;
}
if (string.IsNullOrEmpty(result))
{
result = UniqueID;
}
else
{
Control container = NamingContainer;
if (container != null)
{
if (container is IDataItemContainer)
{
container = container.NamingContainer ?? container;
}
result = container.UniqueID + base.IdSeparator + result;
}
else
{
string uniqueID = UniqueID;
if (!string.IsNullOrEmpty(uniqueID))
{
int index = uniqueID.LastIndexOf(base.IdSeparator);
if (index != -1)
{
result = uniqueID.Substring(0, 1 + index) + result;
}
}
}
}
return result;
}
private void EnsureUniqueGroupName()
{
if (_uniqueGroupName == null)
{
string value = CreateUniqueGroupName();
if (UniqueGroupNameField != null) UniqueGroupNameField.SetValue(this, value);
_uniqueGroupName = value;
value = base.Attributes["value"];
if (string.IsNullOrEmpty(value))
{
base.Attributes["value"] = UniqueID;
}
}
}
protected override bool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
EnsureUniqueGroupName();
return base.LoadPostData(postDataKey, postCollection);
}
protected override void Render(HtmlTextWriter writer)
{
EnsureUniqueGroupName();
base.Render(writer);
}
}
With that control in place and registered using the site prefix, you can change your code to:
<asp:ListView ID="lvwRiskQuestions" runat="server" ItemPlaceholderID="QuestionItemPlaceholder">
<LayoutTemplate>
<asp:PlaceHolder ID="QuestionItemPlaceholder" runat="server" />
</LayoutTemplate>
<ItemTemplate>
<%# Eval("DESCRIPTION") %>
<asp:ListView ID="lvwAnswers" runat="server" ItemPlaceholderID="AnswerItemPlaceholder" DataSource='<%# Eval("Answers")%>'>
<LayoutTemplate>
<asp:PlaceHolder ID="AnswerItemPlaceholder" runat="server" />
</LayoutTemplate>
<ItemTemplate>
<site:ListRadioButton ID="rdbSelect" runat="server"
Text='<%# Eval("Description") %>'
/>
</ItemTemplate>
</asp:ListView>
</ItemTemplate>
</asp:ListView>
In the rendered HTML, the radio-buttons for each question will then have the same name, and you will only be able to select a single answer per question, without having to post the entire page on each selection.
I'd like to point out that this "copy/paste" code doesn't work and was taken from a comment on codeproject (Comment titled Another Option). The original code does work.
Here it is :
using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Reflection;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
public class SimpleRadioButton : RadioButton
{
private static readonly FieldInfo UniqueGroupNameField = FindUniqueGroupNameField();
private string _uniqueGroupName;
private static FieldInfo FindUniqueGroupNameField()
{
return typeof(RadioButton).GetField("_uniqueGroupName",
BindingFlags.NonPublic | BindingFlags.Instance);
}
protected virtual string CreateUniqueGroupName()
{
string result = this.GroupName;
if (string.IsNullOrEmpty(result))
{
result = this.ID;
}
if (string.IsNullOrEmpty(result))
{
result = this.UniqueID;
}
else
{
Control container = this.NamingContainer;
if (null != container)
{
if (container is IDataItemContainer)
{
container = container.NamingContainer ?? container;
}
result = container.UniqueID + base.IdSeparator + result;
}
else
{
string uniqueID = this.UniqueID;
if (!string.IsNullOrEmpty(uniqueID))
{
int index = uniqueID.LastIndexOf(base.IdSeparator);
if (-1 != index)
{
result = uniqueID.Substring(0, 1 + index) + result;
}
}
}
}
return result;
}
private void EnsureUniqueGroupName()
{
if (null == _uniqueGroupName)
{
string value = this.CreateUniqueGroupName();
if (null != UniqueGroupNameField) UniqueGroupNameField.SetValue(this, value);
_uniqueGroupName = value;
// Make sure we have a value attribute:
value = base.Attributes["value"];
if (string.IsNullOrEmpty(value))
{
base.Attributes["value"] = this.UniqueID;
}
}
}
protected override bool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
this.EnsureUniqueGroupName();
return base.LoadPostData(postDataKey, postCollection);
}
protected override void Render(HtmlTextWriter writer)
{
this.EnsureUniqueGroupName();
base.Render(writer);
}
}

Render Macro control on page load in umbraco template

I am trying to load the razor script which exists as a separate macro in umbraco. I am using umbraco 4.7.0
I am basically doing geo-targeting and hence need to run the script each time on a page load. so I am looking for something like :
<script type="c#" runat="server">
protected void Page_Load(object sender, EventArgs e)
{
Call the Macro here
}
Obviously I can do this in the template
<umbraco:Macro Alias="GeoTargetting" runat="server" />
but I need to call this macro before any control is loaded in the page.
PLease help.
Thanks
This appears to work alright:
Template:
<umbraco:Macro Alias="Sandbox" runat="server"></umbraco:Macro>
<asp:Label runat="server" ID="Label1" Text="Yo"></asp:Label>
Macro Script:
#using System.Web.UI.WebControls
#using umbraco.MacroEngines
#inherits DynamicNodeContext
#{
Page page = HttpContext.Current.Handler as Page;
page.Load += new EventHandler(page_Load);
}
#functions
{
static void page_Load(object sender, EventArgs e)
{
Page page = sender as Page;
Label label = FindControlRecursive(page, "Label1") as Label;
label.Text = "Hello";
}
private static Control FindControlRecursive(Control Root, string Id)
{
if (Root.ID == Id)
return Root;
foreach (Control Ctl in Root.Controls)
{
Control FoundCtl = FindControlRecursive(Ctl, Id);
if (FoundCtl != null)
return FoundCtl;
}
return null;
}
}
Note: The FindControlRecursive() method is from this forum thread.

How can I create something like a BoundField that will work in a FormView's templates?

It seems that controls like BoundField only work inside data binding containers like e.g. a GridView, where there is repeating data. I would like to know how to code something like a BoundField that will work e.g. inside the ItemTemplate of a data bound FormView. Just look how much more readable the MyFormViewBoundField is below compared to the raw template way of doing this.
The current way of doing it:
<ItemTemplate>
<div class="span-12 last">
<dl class="name-value">
<dt>Property Type</dt>
<dd><%# Eval("property_type_full") %></dd>
</dl>
</div>
</ItemTemplate>
Compared to what I wish to do:
<ItemTemplate>
<div class="span-12 last">
<mystuff:MyFormViewBoundField LabelText="PropertyType" DataValueField="property_type_full" />
</div>
</ItemTemplate>
You can do this with a simple server Control and customise as required.
public class DataBindField : CompositeControl
{
private HtmlGenericControl dt;
private HtmlGenericControl dd;
public string LabelText { get; set; }
public string DataValueField { get; set; }
protected override void OnDataBinding(EventArgs e)
{
EnsureChildControls();
base.OnDataBinding(e);
object dataItem = DataBinder.GetDataItem(NamingContainer);
if (dataItem != null)
{
dd.InnerText = DataBinder.Eval(dataItem, DataValueField) as string;
}
dt.InnerText = LabelText;
}
protected override void CreateChildControls()
{
base.CreateChildControls();
var dl = new HtmlGenericControl("dl");
dt = new HtmlGenericControl("dt");
dd = new HtmlGenericControl("dd");
dl.Controls.Add(dt);
dl.Controls.Add(dd);
Controls.Add(dl);
}
}
Obviously adding support for ViewState or design-time support requires more work, but that's the basics.

Resources