ASP.net(C#): Custom Templated Control
Source Code
What is a templated control exactly?
Its basically a control that provides us with greater control over the markup rendered by our controls, an example of a templated control in .net is the ListView control.
<asp:ListView runat="server" ID="lv" ItemPlaceholderID="ph"> <LayoutTemplate> <table> <tr> <td> ID </td> <td> Title </td> </tr> </table> </LayoutTemplate> <ItemTemplate> <tr> <td> <%# Eval("ID") %> </td> <td> <%# Eval("Title") %> </td> </tr> </ItemTemplate> </asp:ListView>
In the preceding snippet LayoutTemplate & ItemTemplate represents templated parts of the control.
In order to add this functionality to our own controls, we make use of the ITemplate interface like in the following basic snippet:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace CustomControls { [ParseChildren(ChildrenAsProperties = true)] [Designer(typeof(CustomTemplateDesigner))] public class CustomTemplateControl : CompositeControl, INamingContainer { [Browsable(false)] [PersistenceMode(PersistenceMode.InnerProperty)] [TemplateContainer(typeof(CustomTemplateControl))] public ITemplate FirstTemplate { get; set; } [Browsable(false)] [PersistenceMode(PersistenceMode.InnerProperty)] [TemplateContainer(typeof(CustomTemplateControl))] public ITemplate SecondTemplate { get; set; } protected override void CreateChildControls() { if (FirstTemplate != null) { FirstTemplate.InstantiateIn(this); } if (SecondTemplate != null) { SecondTemplate.InstantiateIn(this); } base.CreateChildControls(); } } }
Notice the properties FirstTemplate & SecondTemplate, these properties expose our templates. Remember to set the PersistenceMode Attribute on these properties in order to persist the contents of these controls (a few MSDN examples excluded it).
Once we drop our control onto a page, these templates become available like this:
<cc:CustomTemplateControl ID="CustomTemplateControl1" runat="server"> <SecondTemplate> 2 </SecondTemplate> <FirstTemplate> 1 </FirstTemplate> </cc:CustomTemplateControl>
We can also add some design time support to our templated control like demonstrated in the following crude snippet:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel.Design; using System.Web.UI.Design; using System.Web.UI; using System.Web.UI.Design.WebControls; using System.ComponentModel; namespace CustomControls { public class CustomTemplateDesigner : CompositeControlDesigner { private CustomTemplateControl _Control; public override void Initialize(IComponent component) { base.Initialize(component); _Control = (CustomTemplateControl)component; } private EditableDesignerRegion GetEditableRegion(ITemplate template, string title, string index, StringBuilder sb) { IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost)); sb.Append(String.Format(@"<tr> <td style=""font-family: Arial;background-color:#CCC""> {0} </td> </tr> <tr> <td {1}='{2}'> {3} </td> </tr>", title, DesignerRegion.DesignerRegionAttributeName, index, ControlPersister.PersistTemplate(template, host))); return new EditableDesignerRegion(this, String.Concat(DesignerRegion.DesignerRegionAttributeName, index), false); } public override string GetDesignTimeHtml(DesignerRegionCollection regions) { StringBuilder sb = new StringBuilder(); sb.Append(@"<table style=""border:1px solid #CCC"">"); EditableDesignerRegion region = GetEditableRegion(_Control.FirstTemplate, "First", "0", sb); EditableDesignerRegion region2 = GetEditableRegion(_Control.SecondTemplate, "Second", "1", sb); sb.Append("</table>"); regions.Add(region); regions.Add(region2); return sb.ToString(); } public override string GetEditableDesignerRegionContent(EditableDesignerRegion region) { IDesignerHost host = (IDesignerHost)Component.Site.GetService(typeof(IDesignerHost)); if (host != null) { ITemplate template = (region.Name == String.Concat(DesignerRegion.DesignerRegionAttributeName, "0")) ? _Control.FirstTemplate : _Control.SecondTemplate; if (template != null) return ControlPersister.PersistTemplate(template, host); } return String.Empty; } public override void SetEditableDesignerRegionContent(EditableDesignerRegion region, string content) { if (content == null) return; IDesignerHost host = (IDesignerHost)Component.Site.GetService(typeof(IDesignerHost)); if (host != null) { ITemplate template = ControlParser.ParseTemplate(host, content); if (region.Name == String.Concat(DesignerRegion.DesignerRegionAttributeName, "0")) _Control.FirstTemplate = template; else _Control.SecondTemplate = template; } } } }
In a future post we will have a look at how to databind templated controls.
Posted by - Christoff Truter
Date - 2010-05-14 23:57:58
Comments - 0
Date - 2010-05-14 23:57:58
Comments - 0
PHP: Accessors (Getters/Setters)
In languages like C# and VB.net one can define access (read/write) to class properties using accessors (get/set).
private string _name; public string name { get { return _name; } set { _name = value; } }
If we were to exclude the set accessor completely, the property becomes read-only, excluding the get accessor (obviously leaving the set accessor intact) makes the property write-only.
But more about that later, in this post we're going to talk about adding this functionality to PHP 5.
A quick way to achieve this is to simply create/use methods to get/set access to a property:
private $name; public get_name() { return $this->name; } public set_name($value) { $this->name = $value; }
This personally doesn't feel like a very "natural" way to access fields - since this involves calling methods and not assigning properties, we can however make it more natural by using "magic methods".
In the following snippet we do exactly that (magic methods __get & __set) by defining a base class containing the functionality to make this work.
abstract class GetterSetter { // Check for property accessibility protected function Accessible($name) { // Check for available accessors if ((method_exists($this, "set_$name")) || (method_exists($this, "get_$name"))) return true; // Inform dev why access to a field was denied throw new Exception((property_exists($this, $name) == false) ? "Property $name does not exist" : "Property $name not accessible"); } public function __get($name) { if ($this->Accessible($name)) { // call get accessor if (method_exists($this, "get_$name")) return $this->{"get_$name"}(); else throw new Exception("Writeonly Property $name"); } } public function __set($name, $value) { if ($this->Accessible($name)) { // call set accessor (if available) if (method_exists($this, "set_$name")) $this->{"set_$name"}($value); else throw new Exception("Readonly Property $name"); } } }
The preceding snippet automatically calls the appropriate methods (accessors), when we read/write to the property/field. To use functionality, simply extend a class.
class person extends GetterSetter { private $Age; private $Name; public $Note; // Not processed by magic get/set methods - since its public. public function __construct($Name) { $this->Name = $Name; } protected function get_Age() { return $this->Age; } protected function set_Age($value) { if ($value < 18) throw new Exception('Invalid age specified'); $this->Age = $value; } protected function get_Name() { return $this->Name; } }
Usage:
$a = new person('Jack'); //$a->Age = 10; // Throws Exception //$a->Age = 19; // Sets the field //$a->Name = "Ben"; // Throws ReadOnly exception //$a->test = 10; // Throws Exception since the field is undefined.
This ultimately provides a mechanism by which we can set constraints on class properties, e.g. field must be of certain type (int/string/bool etc), field must be in certain format (e.g. email)
Posted by - Christoff Truter
Date - 2010-05-11 23:28:30
Comments - 1
Date - 2010-05-11 23:28:30
Comments - 1
First 21 22 23 24 25 26 27 28 29 30 Last / 62 Pages (124 Entries)