I have a class UserControlBase that inherits System.Web.UI.UserControl and my user controls inherit UserControlBase class. UserControlBase has some common functions that are used in all user controls.
I want to put error display function to UserControlBase as well so that I may not have to declare and manage it in all user controls. Error will be displayed in some label in usercontrol. Issue is how to access label which is in usercontrol in UserControlBase in function ? I don't want to pass label as argument.
In your UserControl Base, expose the text value of the label only:
public abstract class UserControlBase : System.Web.UI.UserControl
{
private Label ErrorLabel { get; set; }
protected string ErrorMessage
{
get { return ErrorLabel.Text; }
set { ErrorLabel.Text = value; }
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
ErrorLabel = new Label();
Controls.Add(ErrorLabel);
}
//... Other functions
}
In your user controls that inherit this:
public partial class WebUserControl1 : UserControlBase
{
protected void Page_Load(object sender, EventArgs e)
{
try
{
}
catch (Exception)
{
ErrorMessage = "Error"; //Or whatever
}
}
}
Related
I'm trying to create a factory pattern based on the CompositeControl class.
Everything is working fine. Except as I understand it I have to add the control back onto the placeholder control on my actual page. I've searched around for examples and got one to almost work expect it only worked on the first postback.
I've created a sample here and I'll post all the code here.
Code on my webpage, the most important here is I guess on OnInit where I'm trying to add the control back onto the placeholder, I guess this is what I might be doing wrong.
using SampleControls;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//Setup First Control
Session.Clear();
BaseCompositeControl ltb = new LabelTextBox();
PlaceHolder1.Controls.Add(ltb);
Session.Add("Control", ltb);
}
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
// Check if the post back and recreate the control
if (IsPostBack)
{
int c = this.Form.Controls.Count;
for (int i = 0; i < Session.Count; i++)
{
if (Session[i].ToString().Contains("Control"))
{
this.PlaceHolder1.Controls.Add((BaseCompositeControl)(Session[i]));
}
}
}
}
protected void Button1_Click(object sender, EventArgs e)
{
//Get Postback Date
BaseCompositeControl oltb = (BaseCompositeControl)this.PlaceHolder1.Controls[0];
lblPstBck.Text = oltb.Text;
this.PlaceHolder1.Controls.Clear();
Session.Clear();
//Load next Control
BaseCompositeControl ltb = new LabelCheckBox();
PlaceHolder1.Controls.Add(ltb);
Session.Add("Control", ltb);
}
}
This is composite control classes, I don't know if I have to do something here to handle the viewstate or how?
public abstract class BaseCompositeControl : CompositeControl
{
protected string _Title;
public abstract string Text
{
get;
set;
}
public string Title
{
get { EnsureChildControls();
return _Title; }
set { EnsureChildControls();
_Title = value; }
}
protected override void CreateChildControls()
{
// Clears child controls
Controls.Clear();
// Build the control tree
CreateControlHierarchy();
ClearChildViewState();
}
protected abstract void CreateControlHierarchy();
}
TextBox control
public class LabelCheckBox : BaseCompositeControl
{
protected CheckBox _CheckBox;
public override string Text
{
get
{
EnsureChildControls();
return _CheckBox.Checked.ToString(); ;
}
set
{
EnsureChildControls();
_CheckBox.Checked = Convert.ToBoolean(value);
}
}
protected override void CreateControlHierarchy()
{
_CheckBox = new CheckBox();
Label l = new Label();
// Configure controls
l.Text = "Second Control";
// Connect to the parent
Controls.Add(l);
Controls.Add(_CheckBox);
}
}
Checkbox control
public class LabelTextBox : BaseCompositeControl
{
protected TextBox _Text;
public override string Text
{
get
{
EnsureChildControls();
return _Text.Text;
}
set
{
EnsureChildControls();
_Text.Text = value;
}
}
protected override void CreateControlHierarchy()
{
Label l = new Label();
_Text = new TextBox();
// Configure controls
l.Text = "First Control";
// Connect to the parent
Controls.Add(l);
Controls.Add(_Text);
}
}
I asked this a long time ago,
But I think this is how you should do it. Using a factory pattern for user controls.
http://weblogs.asp.net/sfeldman/archive/2007/12/17/factory-pattern-for-user-controls.aspx
I am developing a web application. I have created an interface ITest
public interface ITest
{
void Add();
}
& a usercontrol which implements ITest
public partial class WebUserControl1 : System.Web.UI.UserControl, ITest
{
public void Add()
{
throw new NotImplementedException();
}
}
On my webpage i have placed usercontrol. but, when i typecast the usercontrol to type IType it throws an Exception(System.InvalidCastException)
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// WebUserControl11.Add();
foreach (var uCnt in this.Page.FindControlsOfType<UserControl>())
{
if (uCnt.Visible)
{
((ITest)uCnt).Add(); //Error : Casting Exception
}
else
{
}
}
}
}
I can call Add method directly but, I want to call it using ITest Interface
I'm not sure how the FindControlsOfType method implemented but suppose that you need to retrieve controls those implement ITest interface instead of all UserControl instances.
I have an asp.net UserControl that writes HTML content from a SharePoint list to a Literal control. Currently I insert a title in h5 tags before each SharePoint list item I write to the Literal. Instead of having the title hardcoded to be placed in h5 tags, I'd like to expose a public property of my user control that lets me define the html format for the title. This is a little different from the templated user control questions I've found so many of because it's not really a template for the user control. I just need a string containing html. Here's what I'm looking to do:
public class MyUserControl: UserControl
{
public string TitleFormat { get; set; }
private void ShowContent()
{
...
string output = String.Format(TitleFormat, title) + someContent;
ltlOutput.Text = output.
}
}
In markup:
<UC:MyUserControl id="muc1" runat="server">
<TitleFormat>
<h3>{0}</h3>
</TitleFormat>
</UC:MyUserControl>
How can I set this up?
Here is the answer (provided by Decker Dong in the asp.net forums):
To nest another class into one, you have to declare a new property but
just declare it is an InnerProperty. And set its Design properties.
Now here's a full sample for you:
[ParseChildren(true),PersistChildren(false)]
public partial class MyUserControl : System.Web.UI.UserControl
{
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[PersistenceMode(PersistenceMode.InnerProperty)]
public string TitleFormat
{
get;
set;
}
protected void Page_Load(object sender, EventArgs e)
{
}
}
With these attributes you can use the control as written in the question.
What you need is http://msdn.microsoft.com/en-us/library/system.web.ui.itemplate.aspx
HTML
<test:NamingControl runat="server" ID="NamingControl" TitleFormat="This is myTitle">
<TitleFormatTemplate>
My title is <%# Container.TitleFormat %>
</TitleFormatTemplate>
</test:NamingControl>
UserControl
public partial class MyUserControl : System.Web.UI.UserControl
{
private ITemplate template;
protected void Page_Load(object sender, EventArgs e)
{
}
public string TitleFormat
{
get;
set;
}
[PersistenceMode(PersistenceMode.InnerProperty),
TemplateContainer(typeof(TitleFormatTemplate))]
public ITemplate TitleFormatTemplate
{
get { return template; }
set { template = value; }
}
protected override void CreateChildControls()
{
base.CreateChildControls();
TitleFormatTemplate t = new TitleFormatTemplate();
t.TitleFormat = this.TitleFormat;
template.InstantiateIn(t);
this.Controls.Add(t);
this.DataBind();
}
}
Child Control - INamingContainer
public class TitleFormatTemplate : Control, INamingContainer
{
private string _TitleFormat = "";
public string TitleFormat
{
get { return _TitleFormat; }
set { _TitleFormat = value; }
}
}
The simpler approach - No more TitleFormat tag
MyUserControl.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="MyUserControl.ascx.cs"
Inherits="testgingweb.usrcontrols.MyUserControl" %>
<h3><asp:Label runat="server" ID="PassedValueLabel"></asp:Label</h3>
The Codebehind - MyUserControl.ascx.cs
public string TitleFormat
{
get { return ViewState["TitleFormat"]; }
set { ViewState["TitleFormat"] = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
PassedValueLabel.Text = String.Format("Whatever {0} here", this.TitleFormat);
}
HTML
<test:MyUserContorl runat="server" ID="NamingControl" TitleFormat="This is myTitle">
</test:MyUserContorl>
Notice that I didn't have the TitleFormat tag anymore.
The First - LblTextBox:
A label and textbox that have a LabelText field that can be set to change the label text
The Second - LoginCtl:
A login control that has two instances of LblTextBox for user name, password and a submit button
I want to control the tag rendering of these controls for formatting so I am not overriding CreateChildControls() to get the job done.
My issue is that the controls are rendered but none of the OnInit() code in either controls takes hold (blank labels, css styles not applied, etc..).
Any direction would be great!
public class LblTextBox : CompositeControl
{
public string LabelText { get; set; }
public string Text { get; set; }
TextBox input;
Label label;
RequiredFieldValidator evalReqField;
public LblTextBox()
{
label = new Label();
input = new TextBox();
evalReqField = new RequiredFieldValidator();
}
protected override void OnInit(EventArgs e)
{
label.ID = "lblTextBox";
label.Text = string.Format("{0}:", LabelText);
input.ID = "tbInput";
evalReqField.ID = "evalInput";
evalReqField.ControlToValidate = input.ID;
evalReqField.ErrorMessage = "(Required)";
evalReqField.Display = ValidatorDisplay.Dynamic;
}
protected override void RenderChildren(HtmlTextWriter writer)
{
writer.RenderBeginTag(HtmlTextWriterTag.Div);
label.RenderControl(writer);
input.RenderControl(writer);
evalReqField.RenderControl(writer);
writer.RenderEndTag();
}
}
public class LoginCtl : CompositeControl
{
public string UserName
{
get
{
return (ltbUser != null) ? ltbUser.Text : string.Empty;
}
set
{
if (ltbUser != null)
ltbUser.Text = value;
}
}
public string Password
{
get
{
return (ltbPass != null) ? ltbPass.Text : string.Empty;
}
set
{
if (ltbPass != null)
ltbPass.Text = value;
}
}
private LblTextBox ltbUser;
private LblTextBox ltbPass;
private Button btnSubmit;
public LoginCtl()
{
ltbUser = new LblTextBox();
ltbPass = new LblTextBox();
btnSubmit = new Button();
}
protected override void OnInit(EventArgs e)
{
ltbUser.LabelText = "User Name";
ltbPass.LabelText = "Password";
btnSubmit.Text = "Submit";
btnSubmit.CssClass = "Submit";
}
protected override void RenderChildren(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Class, "LoginCtlDiv");
writer.RenderBeginTag(HtmlTextWriterTag.Div);
ltbUser.RenderControl(writer);
ltbPass.RenderControl(writer);
btnSubmit.RenderControl(writer);
writer.RenderEndTag();
}
}
The goal was to be able to set properties in the aspx Markup using the control. However, the properties were never initialized.
My error was in the understanding of using CreateChildControls() and RenderChildren(..)
I thought that it was to use one or the other. Instead, I instantiate all the child controls and add them in CreateChildControls().
In order to load the properties, I wait till the OnPreRender() event. The controls will all be loaded and so will the data. Then I make the final changes before the control is rendered to the page.
Another little note, I really wanted to change the default tag that is wrapped around my controls for display purposes (ASP will wrap it with a span by default). So if you want a block level elem this will cause a problem. If you override the TagKey property and set it to an enum elem it will use that instead of the default span tag.
I restructured it as the following:
public class LblTextBox : CompositeControl
{
protected override void OnPreRender(EventArgs e)
{
label.Text = string.Format("{0}:", LabelText);
base.OnPreRender(e);
}
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Div;
}
}
protected override void CreateChildControls()
{
label = new Label();
input = new TextBox();
evalReqField = new RequiredFieldValidator();
label.ID = "lblTextBox";
input.ID = "tbInput";
evalReqField.ID = "evalInput";
evalReqField.ControlToValidate = input.ID;
evalReqField.ErrorMessage = "(Required)";
evalReqField.Display = ValidatorDisplay.Dynamic;
Controls.Add(label);
Controls.Add(input);
Controls.Add(evalReqField);
base.CreateChildControls();
}
public string LabelText { get; set; } //label text
public string Text { get; set; } //text in textbox
TextBox input;
Label label;
RequiredFieldValidator evalReqField;
}
public class LoginCtl : CompositeControl
{
protected override void CreateChildControls()
{
ltbUser = new LblTextBox();
ltbPass = new LblTextBox();
btnSubmit = new Button();
ltbUser.LabelText = "User Name";
ltbPass.LabelText = "Password";
ltbPass.MargBetween = "10px";
btnSubmit.Text = "Submit";
btnSubmit.CssClass = "Submit";
Controls.Add(ltbUser);
Controls.Add(ltbPass);
Controls.Add(btnSubmit);
}
//..
//..
private LblTextBox ltbUser;
private LblTextBox ltbPass;
private Button btnSubmit;
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Div;
}
}
}
I don't remember why (I'll try to recall), but I had very similar problem few months ago, and my solution was to initialize all of properties except of "ID" in OnLoad event handler:
protected override void OnLoad(EventArgs e)
{
label.Text = string.Format("{0}:", LabelText);
evalReqField.ControlToValidate = input.ID;
evalReqField.ErrorMessage = "(Required)";
evalReqField.Display = ValidatorDisplay.Dynamic;
}
Hope this helps
I have a simple web control (TaskList) that can have children (Task) which inherit from LinkButton, that can be added declaratively or programatically. This works ok, but I can't get the onclick event of a Task to be fired in my code behind. The code ..
[ToolboxData("<{0}:TaskList runat=\"server\"> </{0}:TaskList>")]
[ParseChildren(true)]
[PersistChildren(false)]
public class TaskList : System.Web.UI.Control
{
//[DefaultProperty("Text")]
public TaskList()
{}
private List<Task> _taskList = new List<Task>();
private string _taskHeading = "";
public string Heading
{
get
{
return this._taskHeading;
}
set
{
this._taskHeading = value;
}
}
[NotifyParentProperty(true)]
[PersistenceMode(PersistenceMode.InnerProperty)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public List<Task> Tasks
{
get
{
return this._taskList;
}
set
{
this._taskList = value;
}
}
protected override void CreateChildControls()
{
foreach (Task task in this._taskList)
this.Controls.Add(task);
base.CreateChildControls();
}
protected override void Render(HtmlTextWriter writer)
{
writer.Write("<h2>" + this._taskHeading + "</h2>");
writer.Write("<div class='tasks_container'>");
writer.Write("<div class='tasks_list'>");
writer.Write("<ul>");
foreach (Task task in this._taskList)
{
writer.Write("<li>");
task.RenderControl(writer);
writer.Write("</li>");
}
writer.Write("</ul>");
writer.Write("</div>");
writer.Write("</div>");
}
}
public class Task : LinkButton
{
private string _key = "";
public string Key
{
get
{
return this._key;
}
set
{
this._key = value;
}
}
}
Markup:
<rf:TaskList runat="server" ID="tskList" Heading="Tasks">
<Tasks>
<rf:Task Key="ba" ID="L1" Text="Helllo" OnClick="task1_Click" runat="server" />
</Tasks>
</rf:TaskList>
The Onclick event task1_Click never fires when clicked (although a postback occurs).
TaskList needed to implement INamingContainer to correctly route the events of each Task.
You could also inherit from CompositeControl, which implements INamingContainer for you, instead of inheriting from Control.
Have you thought about INamingContainer.