I'm trying to learn how to use ITemplate for nicer custom controls. I have it mostly working but I haven't been able to figure out how to access any properties of the container from the page.
Here is my templated control:
[ParseChildren(true)]
[PersistChildren(false)]
public partial class Example : UserControl
{
private ITemplate _CustomPanelContainer;
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateContainer(typeof(CustomPanelContainer))]
[TemplateInstance(TemplateInstance.Single)]
public virtual ITemplate CustomPanel
{
get { return _CustomPanelContainer; }
set { _CustomPanelContainer = value; }
}
protected override void CreateChildControls()
{
Controls.Clear();
if (_CustomPanelContainer != null)
{
var p = new Panel();
p.ID = "CustomPanel";
Controls.Add(p);
_CustomPanelContainer.InstantiateIn(p);
}
base.CreateChildControls();
}
public class CustomPanelContainer : Panel, INamingContainer
{
private string _Test = "TESTING!";
public string TextTest
{
get
{
return _Test;
}
set
{
_Test = value;
}
}
}
}
Here is the page implementation:
<uc1:Example runat="server" ID="Example1">
<CustomPanel>
<strong>Test: </strong> <%# Container.TextTest %>
</CustomPanel>
</uc1:Example>
It is mostly working but the problem is that <%# Container.TextTest %> always returns an empty string. When I run it on the debugger, I put a breakpoint at the line inside the TextTest property of CustomPanelContainer and the breakpoint is never hit, so the property is never actually being accessed.
What am I missing here? How do I enable access to the container's public properties via <%#Container ?
I finally figured out how to make it act the way I want.
I removed ITemplate as the type of the Container and set the type as the actual type and added a DataBind() command to CreateChildControls().
Maybe not quite the correct way to do this, but it works.
Keeping the question open for a bit to see if anyone offers any critique or a better approach, since I really don't know what I'm doing here yet.
Simplified Working code:
[ParseChildren(true)]
[PersistChildren(false)]
public partial class Example : UserControl
{
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateInstance(TemplateInstance.Single)]
public virtual CustomPanelContainer Template { get; set; }
protected override void CreateChildControls()
{
Controls.Clear();
if (Template != null)
{
Template.DataBind();
Controls.Add(Template);
}
base.CreateChildControls();
}
public class CustomPanelContainer : Panel, INamingContainer
{
public string TextTest
{
get { return "TESTING!"; }
}
}
}
Page Implementation:
<uc1:Example runat="server" ID="Example">
<Template>
<strong>Test: </strong><span><%# Container.TextTest %></span>
</Template>
</uc1:Example>
EDIT: This also works when needing to hide the type of the template.
i,e., the code above exposes the type of Template to allow manipulating properties of the Panel as attributes of Template, whereas the code below hides the type of Template to block manipulation of its properties.
[ParseChildren(true)]
[PersistChildren(false)]
public partial class Example : UserControl
{
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateInstance(TemplateInstance.Single)]
[TemplateContainer(typeof(CustomPanelContainer))]
public virtual ITemplate Template { get; set; }
protected override void CreateChildControls()
{
Controls.Clear();
if (Template != null)
{
var p = new CustomPanelContainer();
Template.InstantiateIn(p);
p.DataBind();
Controls.Add(p);
}
base.CreateChildControls();
}
public class CustomPanelContainer : Panel, INamingContainer
{
public string TextTest
{
get { return "TESTING!"; }
}
}
Related
When you create a ListView, there is a property on the control that allows you to specify the ID of the PlaceHolder in the LayoutTemplate that is used to hold the controls for each item.
<asp:ListView ID="lvTest" runat="server" ItemPlaceholderID="testPlaceholder">
<LayoutTemplate>
<ul>
<asp:PlaceHolder ID="testPlaceholder" runat="server" />
</ul>
</LayoutTemplate>
<ItemTemplate>
<li>Item</li>
</ItemTemplate>
</asp:ListView>
I am trying to create a custom templated server control but would like to have a property on the template itself as I expect to have several different templates. My extremely simplified, trivial example is as follows:
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ControlLibrary
{
[ParseChildren(true)]
public class TestContainer : Control, INamingContainer
{
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateContainer(typeof(TestContainer))]
public TestTemplate TestTemplate { get; set; }
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
DataBind();
}
public override void DataBind()
{
base.DataBind();
CreateChildControls();
}
protected override void CreateChildControls()
{
Controls.Clear();
var phTest = new PlaceHolder();
phTest.ID = "phTest";
Controls.Add(phTest);
if (this.TestTemplate != null)
this.TestTemplate.InstantiateIn(phTest);
this.ChildControlsCreated = true;
}
}
public class TestTemplate : ITemplate
{
public string Name { get; set; }
public void InstantiateIn(Control container)
{
container.Controls.Add(new LiteralControl(this.Name));
}
}
}
However, if I add the template to my .aspx file like below I get an error saying CS0029: Cannot implicitly convert type 'System.Web.UI.CompiledTemplateBuilder' to 'ControlLibrary.TestTemplate'
<CustomControls:TestContainer ID="testContainer" runat="server">
<TestTemplate>
test
</TestTemplate>
</CustomControls:TestContainer>
Is it possible to do this or will I have to put all configurable properties on the parent container itself?
Thanks for any help you can provide!
You did everything correctly except the template property declaration. Any template must be declared as System.Web.UI.ITemplate. Just replace your template declaration with:
public ITemplate TestTemplate { get; set; }
And it should start working. For reference see How to: Create Templated ASP.NET User Controls.
To do a trick with custom attributes for template you need to add one more class inheriting from collection:
public class TestTemplateList : List<TestTemplate> { }
And change declaration of the control as following:
[ParseChildren(true, DefaultProperty = "TestTemplates")]
public class TestContainer : Control, INamingContainer
{
[PersistenceMode(PersistenceMode.InnerProperty)]
public TestTemplateList TestTemplates { get; set; }
// ... OnLoad and DataBind left intact
protected override void CreateChildControls()
{
Controls.Clear();
var phTest = new PlaceHolder();
phTest.ID = "phTest";
Controls.Add(phTest);
if (this.TestTemplates != null)
{
foreach (var testTemplate in TestTemplates)
{
((ITemplate)testTemplate).InstantiateIn(phTest);
}
}
this.ChildControlsCreated = true;
}
}
After that you should be able to declare control in both ways. You can skip specifying TestTemplates because it is declared as a DefaulProperty in ParseChildrenAttribute:
<CustomControls:TestContainer runat="server" ID="testContainer">
<CustomControls:TestTemplate Name="test">
</CustomControls:TestTemplate>
</CustomControls:TestContainer>
<%-- OR --%>
<CustomControls:TestContainer runat="server" ID="wc11">
<TestTemplates>
<CustomControls:TestTemplate Name="test">
</CustomControls:TestTemplate>
</TestTemplates>
</CustomControls:TestContainer>
I wrote User Control (yay!). But I want it to behave as a container. But wait! I know about
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design",
typeof(IDesigner))]
Trick.
The problem is - I don't want all of my control to behave like container, but only one part. One - de facto - panel ;)
To give wider context: I wrote a control that has Grid, some common buttons, labels and functionalities. But it also has a part where the user is supposed to drop his custom buttons/controls whatever. Only in this particular part of the control, nowhere else.
Anyone had any idea?
You should do the following :
For your user control, you need to create a new designer which enables the inner panel on design-time by calling EnableDesignMode method.
For the inner panel, you need to create a designer which disables moving, resizing and removes some properties from designer.
You should register the designers.
Example
You can read a blog post about this topic here and clone or download a working example:
r-aghaei/ChildContainerControlDesignerSample
Download Zip
Code
Here is the code for different elements of the solution.
Your user control
[Designer(typeof(MyUserControlDesigner))]
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
TypeDescriptor.AddAttributes(this.panel1,
new DesignerAttribute(typeof(MyPanelDesigner)));
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public Panel ContentsPanel
{
get { return panel1; }
}
}
Designer for the inner panel
public class MyPanelDesigner : ParentControlDesigner
{
public override SelectionRules SelectionRules
{
get
{
SelectionRules selectionRules = base.SelectionRules;
selectionRules &= ~SelectionRules.AllSizeable;
return selectionRules;
}
}
protected override void PostFilterAttributes(IDictionary attributes)
{
base.PostFilterAttributes(attributes);
attributes[typeof(DockingAttribute)] =
new DockingAttribute(DockingBehavior.Never);
}
protected override void PostFilterProperties(IDictionary properties)
{
base.PostFilterProperties(properties);
var propertiesToRemove = new string[] {
"Dock", "Anchor", "Size", "Location", "Width", "Height",
"MinimumSize", "MaximumSize", "AutoSize", "AutoSizeMode",
"Visible", "Enabled",
};
foreach (var item in propertiesToRemove)
{
if (properties.Contains(item))
properties[item] = TypeDescriptor.CreateProperty(this.Component.GetType(),
(PropertyDescriptor)properties[item],
new BrowsableAttribute(false));
}
}
}
Designer for your user control
public class MyUserControlDesigner : ParentControlDesigner
{
public override void Initialize(IComponent component)
{
base.Initialize(component);
var contentsPanel = ((MyUserControl)this.Control).ContentsPanel;
this.EnableDesignMode(contentsPanel, "ContentsPanel");
}
public override bool CanParent(Control control)
{
return false;
}
protected override void OnDragOver(DragEventArgs de)
{
de.Effect = DragDropEffects.None;
}
protected override IComponent[] CreateToolCore(ToolboxItem tool, int x,
int y, int width, int height, bool hasLocation, bool hasSize)
{
return null;
}
}
I've created my custom control. It has a property that is called "Tab." This property adds a collection of "FloorsInformation" controls that are inherited from "DockContainerItem" class to my custom control.
Now, I want to add "FloorsInformation" controls to my custom control after click the "OK" button of the Tab "CollectionEditor" window.
I have "AddTabs" method for doing that. However, I can't call it in the right place. I must call "AddTabs" method in "set accessor" of the "Tab" property, but it never occurs.
I also can call this method from "get accessor" of the "Tab" property, but calling this method in "get accessor" of the "Tab" property will result in an error, because the program access to the "get accessor" of the "Tab" property continuously.
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
[ToolboxItem(true), ToolboxBitmap(typeof(ToolboxIconResourceFinder), "FloorsGrouping.bmp")]
[DisplayName("Floors Group")]
[Editor("WindowsFormsControlLibrary2.FloorsGrouping, WindowsFormsControlLibrary2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=197889249da45bfc", typeof(UITypeEditor))]
[Description("Floorssssssss")]
[Category("Saino")]
[DefaultProperty("Text")]
[DesignerCategory("Component")] //Form //Designer //Empty String ("")
public partial class FloorsGrouping : Bar
{
private Tabs tabs = new Tabs();
public FloorsGrouping()
{
InitializeComponent();
this.AutoHide = true;
}
[Category("Data")]
[DisplayName("Tabs")]
[Description("Tabsssssssssssss")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Editor(typeof(ItemsCollectionEditor), typeof(UITypeEditor))]
public Tabs Tab
{
get
{
//AddTabs();
return tabs;
}
//set
//{
//AddTabs();
//}
}
public void AddTabs()
{
foreach (DockContainerItem dciItem in Tab)
{
if (!Parent.Controls.ContainsKey(dciItem.Name))
{
Items.Add(dciItem);
}
}
}
}
[DisplayName("Floors Information")]
[Description("Floors Informationnnnnnnnnnnnnnnn")]
[DefaultProperty("Text")]
[DesignerCategory("Component")]
[ToolboxItem(false)]
public class FloorsInformation : DockContainerItem
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
private SimilarFloorsInformation similarFloorsInformation = new SimilarFloorsInformation();
private AllFloorsInformation allFloorsInformation = new AllFloorsInformation();
private string text = "Floors Information";
public FloorsInformation()
{
}
[Category("Data")]
[DisplayName("Similar Floors Panel")]
[Description("Similar Floors Panellllllllllllllllllll")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public SimilarFloorsInformation SimilarFloorsInfo
{
get
{
return similarFloorsInformation;
}
set
{
similarFloorsInformation = value;
}
}
[Category("Data")]
[DisplayName("All Floors Group")]
[Description("All Floors Groupppppppppppppp")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public AllFloorsInformation AllFloorsInfo
{
get
{
return allFloorsInformation;
}
set
{
allFloorsInformation = value;
}
}
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
}
public class Tabs : CollectionBase
{
public FloorsInformation this[int intIndex]
{
get
{
return (FloorsInformation)InnerList[intIndex];
}
set
{
InnerList[intIndex] = value;
}
}
public int Add(FloorsInformation finfItemType)
{
return InnerList.Add(finfItemType);
}
public bool Contains(FloorsInformation finfItemType)
{
return InnerList.Contains(finfItemType);
}
public void Remove(FloorsInformation finfItemType)
{
InnerList.Remove(finfItemType);
}
public void Insert(int intIndex, FloorsInformation finfItemType)
{
InnerList.Insert(intIndex, finfItemType);
}
public FloorsInformation[] GetValues()
{
FloorsInformation[] finfItemType = new FloorsInformation[InnerList.Count];
InnerList.CopyTo(0, finfItemType, 0, InnerList.Count);
return finfItemType;
}
}
By the way, I can call this method in "SetItems" overrode method of the "ItemsCollectionEditor" class that is inherited from "CollectionEditor" class; nevertheless, I can't access to "AddTabs" method without create a new instance of my custom control class. If I create a new instance of my custom control, "AddTabs" method applies changes on a new control of my custom control and not on the current added custom control in the WinForm.
public class ItemsCollectionEditor : CollectionEditor
{
private Type[] typItems;
public ItemsCollectionEditor(Type typItem)
: base(typItem)
{
typItems = new Type[] { typeof(FloorsInformation) };
}
protected override Type[] CreateNewItemTypes()
{
return typItems;
}
protected override CollectionForm CreateCollectionForm()
{
CollectionForm collectionForm = base.CreateCollectionForm();
collectionForm.Text = "Tabs Collection Editor";
return collectionForm;
//return base.CreateCollectionForm();
}
protected override object SetItems(object editValue, object[] value)
{
return base.SetItems(editValue, value);
}
}
What must I do for achieve to my goal?
You have a couple of options.
Option 1:
If you are just wanting to expose the FloorsGrouping.Items property at design time, you can change the Tab property's type to SubItemsCollection and return the Items property. In this case, you won't have to worry about intercepting any collection change events, it will happen for you automatically.
[Category("Data")]
[DisplayName("Tabs")]
[Description("Tabsssssssssssss")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Editor(typeof(ItemsCollectionEditor), typeof(UITypeEditor))]
public SubItemsCollection Tab {
get {
return Items;
}
}
Option 2:
If you are needing to intercept the collection change events, modify the Tabs class to inherit from ObservableCollection<FloorsInformation>, which implements INotifyCollectionChanged.
public class Tabs : System.Collections.ObjectModel.ObservableCollection<FloorsInformation> {
}
And in your FloorsGrouping constructor, subscribe to the CollectionChanged event.
public FloorsGrouping() {
...
tabs.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(tabs_CollectionChanged);
}
Finally, in your event handler, process the collection change.
private void tabs_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
switch (e.Action) {
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
foreach (DockContainerItem dciItem in e.NewItems) {
if (!Parent.Controls.ContainsKey(dciItem.Name))
Items.Add(dciItem);
}
break;
case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
Items.Clear();
break;
}
}
What you'll notice with option 2 is that the CollectionChanged event fires in real time with the editing in the collection editor, not specifically when the OK button is clicked. However, when the user finally clicks the OK or Cancel button in the collection editor, the collection's state is accurate.
I'm building my first custom server control which inherits from CompositeControl
The reason for the control is to be able to have a consistent content area (HTML elements) for multiple online applications that we develop.
So instead of having to constantly type out:
<div class="titleBar">
</div>
<div class="actionBar">
</div>
<div class="workspace">
</div>
the developer could add a server control as follows:
<custom:Workspace id="..." runat="server" Title="MyTitle">
<TitleBar>
Here is the title
</TitleBar>
<ActionBar>
<asp:button id="..." runat="server" Title="MyButton" />
</ActionBar>
<Content>
<asp:DataGrid id="..." runat="server" />
</Content>
</custom:Workspace>
I read the article at http://msdn.microsoft.com/en-us/library/ms178657.aspx and it works, but the problem is... I don't understand why. (Does anyone have a link to a layman's version of an article that describes how to build these kinds of server controls?)
Main thing I notice so far is that Asp.net is rendering a bunch of SPAN elements, which of course I don't want.
How does one control the HTML that the new CompositeControl is outputting?
Thanks,
Jacques
PS. Here's my code so far:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.Design;
namespace TemplatedServerControl
{
[DefaultProperty("Title")]
[ToolboxData("<{0}:Workspace runat=server></{0}:Workspace>")]
public class Workspace : CompositeControl
{
#region FIELDS
private ITemplate _TitleBarTemplateValue;
private ITemplate _ActionBarTemplateValue;
private TemplateOwner _TitleBarOwnerValue;
private TemplateOwner _ActionBarOwnerValue;
#endregion
#region PROPERTY - TitleBarOwner
[Browsable(false),
DesignerSerializationVisibility(
DesignerSerializationVisibility.Hidden)]
public TemplateOwner TitleBarOwner
{
get
{
return _TitleBarOwnerValue;
}
}
#endregion
#region PROPERTY - ActionBarOwner
[Browsable(false),
DesignerSerializationVisibility(
DesignerSerializationVisibility.Hidden)]
public TemplateOwner ActionBarOwner
{
get
{
return _ActionBarOwnerValue;
}
}
#endregion
#region PROPERTY - Title
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("[Provide the title for the workspace]")]
[Localizable(true)]
public string Title
{
get
{
String s = (String)ViewState["Title"];
return ((s == null) ? "[" + this.ID + "]" : s);
}
set
{
ViewState["Text"] = value;
}
}
#endregion
#region PROPERTY - TitleBar
[Browsable(false),
PersistenceMode(PersistenceMode.InnerProperty),
DefaultValue(typeof(ITemplate), ""),
Description("Control template"),
TemplateContainer(typeof(Workspace))]
public virtual ITemplate TitleBar
{
get
{
return _TitleBarTemplateValue;
}
set
{
_TitleBarTemplateValue = value;
}
}
#endregion
#region PROPERTY - ActionBar
[Browsable(false),
PersistenceMode(PersistenceMode.InnerProperty),
DefaultValue(typeof(ITemplate), ""),
Description("Control template"),
TemplateContainer(typeof(Workspace))]
public virtual ITemplate ActionBar
{
get
{
return _ActionBarTemplateValue;
}
set
{
_ActionBarTemplateValue = value;
}
}
#endregion
#region METHOD - CreateChildControls()
protected override void CreateChildControls()
{
//base.CreateChildControls();
Controls.Clear();
_TitleBarOwnerValue = new TemplateOwner();
_ActionBarOwnerValue = new TemplateOwner();
ITemplate temp1 = _TitleBarTemplateValue;
ITemplate temp2 = _ActionBarTemplateValue;
temp1.InstantiateIn(_TitleBarOwnerValue);
temp2.InstantiateIn(_ActionBarOwnerValue);
this.Controls.Add(_TitleBarOwnerValue);
this.Controls.Add(_ActionBarOwnerValue);
}
#endregion
#region METHOD - RenderContents(HtmlTextWriter writer)
protected override void RenderContents(HtmlTextWriter writer)
{
base.RenderContents(writer);
}
#endregion
}
[ToolboxItem(false)]
public class TemplateOwner : WebControl
{
}
}
The extra <span> elements are coming from the TemplateOwner controls because a WebControl (which TemplateOwner inherits from) renders <span> tags by default. You could change TemplateOwner to specify the tag to render:
public class TemplateOwner : WebControl
{
public TemplateOwner() :
base(HtmlTextWriterTag.Div)
{
}
}
But you don't need to create your own class to use templates. For example, you can just use Panel controls:
private Panel _TitleBarPanel;
private Panel _ActionBarPanel;
protected override void CreateChildControls()
{
_TitleBarPanel = new Panel { CssClass = "titleBar" };
_TitleBarTemplateValue.InstantiateIn(_TitleBarPanel);
this.Controls.Add(_TitleBarPanel);
_ActionBarPanel = new Panel { CssClass = "actionBar" };
_ActionBarTemplateValue.InstantiateIn(_ActionBarPanel);
this.Controls.Add(_ActionBarPanel);
}
A simpler solution us to use the PlaceHolder control.
Like CompositeControl, this is a container control.
Unlike CompositeControl however, it doesn't render any content at all - no containing or tags.
It does mean that you can't refer to the entire control programatically, like you can with a CompositeControl, but depending on what you are doing, that may not be necessary.
Each subcontrol will have a unique ID though, so you can refer to child controls programatically (deal with events etc)
I have a server control, inheriting from PlaceHolder.
Basically, all it is, is a placeholder, with the top part having a "<div class etc...", and the bottom closing it off.
So, typical usage would be
<control:control runat="server" id="phControl">
<asp:TextBox runat="server" id="txtControl">
<asp:DropDownList runat="server"id="ddlControl">
</control:control>
or something similar.
It has struck me that if I postback to the control, it loses all the items in the ddlControl (or whatever), and that implementing IPostBackHandler apparently would solve all my woes.
I had a quick glance through the documentation, but am still not really sure what I am implementing (obviously I have the method names, but I don't really get what is expected in here)
Any pointers in the right direction would be greatly appreciated.
Thanks,
Tim
Its looks like you just want a server control that can contains other controls or a "template", I have just done this using the example at: http://msdn.microsoft.com/en-us/library/ms178657.aspx
This should handle all the work done on postback.
A basic example adapted from the above link:
using System;
using System.ComponentModel;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.WebControls;
namespace Made4Print.Web.UI
{
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal), Designer(typeof(VacationHomeDesigner)), DefaultProperty("Title"), ToolboxData("<{0}:TemplateContainer runat=\"server\"> "),]
public class TemplateContainer : CompositeControl
{
private ITemplate templateValue;
private TemplateOwner ownerValue;
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public TemplateOwner Owner
{
get
{
return ownerValue;
}
}
[Browsable(false), PersistenceMode(PersistenceMode.InnerProperty), DefaultValue(typeof(ITemplate), ""), Description("Control template"), TemplateContainer(typeof(TemplateContainer))]
public virtual ITemplate Template
{
get
{
return templateValue;
}
set
{
templateValue = value;
}
}
protected override void CreateChildControls()
{
Controls.Clear();
ownerValue = new TemplateOwner();
ITemplate temp = templateValue;
if (temp == null)
{
temp = new DefaultTemplate();
}
temp.InstantiateIn(ownerValue);
this.Controls.Add(ownerValue);
}
public override void DataBind()
{
CreateChildControls();
ChildControlsCreated = true;
base.DataBind();
}
}
[ToolboxItem(false)]
public class TemplateOwner : WebControl
{
}
#region DefaultTemplate
sealed class DefaultTemplate : ITemplate
{
void ITemplate.InstantiateIn(Control owner)
{
// Create Controls Here
//Label title = new Label();
//title.DataBinding += new EventHandler(title_DataBinding);
//owner.Controls.Add(title);
}
//void title_DataBinding(object sender, EventArgs e)
//{
// Label source = (Label)sender;
// TemplateContainer container = (TemplateContainer)(source.NamingContainer);
// source.Text = container.Title;
//}
}
#endregion
public class VacationHomeDesigner : ControlDesigner
{
public override void Initialize(IComponent Component)
{
base.Initialize(Component);
SetViewFlags(ViewFlags.TemplateEditing, true);
}
public override string GetDesignTimeHtml()
{
return "<span>[Template Container Control]</span>";
}
public override TemplateGroupCollection TemplateGroups
{
get
{
TemplateGroupCollection collection = new TemplateGroupCollection();
TemplateGroup group;
TemplateDefinition template;
TemplateContainer control;
control = (TemplateContainer)Component;
group = new TemplateGroup("Item");
template = new TemplateDefinition(this, "Template", control, "Template", true);
group.AddTemplateDefinition(template);
collection.Add(group);
return collection;
}
}
}
}