Adding controls to EditableDesignerRegion/ITemplate in code.

  • Thread starter Christophe Peillet
  • Start date
C

Christophe Peillet

I have a base custom control called 'WebBox' that contains a single
EditableDesignerRegion. The contents of this EditableDesignerRegion are
stored in an ITemplate via a property name 'Content', and serialized as an
InnerProperty.

This all works as expected, renders properly, etc., but I can't figure out
how, in a control that inherits WebBox (such as AdvertisementWebBox,
SearchWebBox, etc.) to add controls to the ITemplate in code on the Server
Side. If I add things in the markup, as below, everything works fine (see
inner property names 'Content').

<CompanyUI:WebBox ID="SearchWebBox" runat="server" IconWidth="0"
SkinID="SearchBox"
Title="Search" TitleVisible="True" Width="180px">
<Content>
<div style="text-align: center">
<table border="0" cellpadding="0" cellspacing="0"
style="width: 100%">
<tr>
<td align="left" style="width: 130px" valign="top">
<CompanyUI:AdvancedTextBox ID="AdvancedTextBox1"
runat="server" LabelPosition="Bottom"

Width="130px"></CompanyUI:AdvancedTextBox></td>
<td align="center" valign="top">
<CompanyUI:AdvancedButton ID="SearchButton"
runat="server" Text="go" /></td>
</tr>
<tr>
<td align="left" colspan="2" style="width: 130px"
valign="top">
<CompanyUI:CompanyHyperLink
ID="AdvancedSearchLink" runat="server" Description="" LinkLeaderCssClass=""
LinkLeaderImageCssClass=""
LinkLeaderImageUrl="" NavigateUrl="~/AdvancedSearch.aspx"
TextResourceKey="AdvancedSearch">Advanced
Search</CompanyUI:CompanyHyperLink></td>
</tr>
</table>
</div>
</Content>
</CompanyUI:WebBox>

How can I do this in code in another specialized server control, though?

In the server control that inherits WebBox, I have tried the following, but
with no success.

protected override void OnPreRender(EventArgs e)
{
// Call underlying OnPreRender method
base.OnPreRender(e);

if (!(this.DesignMode))
{
// Clear WebBox .Content control collection
Control template = new Control();
base.Content.InstantiateIn(template);

// ToDo: How to add controls to an ITemplate in code?

template.Controls.Clear();

... // Add controls to collection
... template.Controls.Add(...) ...
}
}

I want WebBox as a generic control with an empty ITemplate, and in
specialized controls that inherit from it to add controls like Search boxes,
link listings, etc.

Any help on this would be appreciated.
 
S

Steven Cheng[MSFT]

Thank you for posting,

As for the Template based control in ASP.NET, the template property
(ITemplate) can not be created like normal control(by adding new controls
into Controls collection). If we want to dynamically populate an template
and use it in any Template based control, we need to create a custom
Template class and add our custom code logic in the Template's code. Here
are the msdn reference described programmatically creating ASP.NET server
control template:

#Creating Web Server Control Templates Dynamically
http://msdn.microsoft.com/library/en-us/vbcon/html/vbtskcreatingwebservercon
troltemplatesdynamically.asp?frame=true

#Creating Templates Programmatically in the DataGrid Control
http://msdn.microsoft.com/library/en-us/vbcon/html/vbtskcreatingtemplatespro
grammaticallyindatagridcontrol.asp?frame=true

Hope this helps.

Regards,

Steven Cheng
Microsoft Online Community Support


==================================================

When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.

==================================================


This posting is provided "AS IS" with no warranties, and confers no rights.



Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
C

Christophe Peillet

After looking at these examples, I'm still a bit lost. I have made a class
that implements ITemplate, but still do not see how I can get access to
something similar to a ControlCollection to add objects inside the template
at run time. The ITemplate class is included below.

The example you gave me has a bit of code in the InstantiateIn method (using
a switch), but I don't see how this is relevant to my needs. I only have one
template, and simply need to be able to insert (via code) any controls into
it, via something like 'MyServerControl.Content.Controls.Add(x);' when
..Content is the ITemplate (or, in this case, 'WebBoxTemplate'). Sorry to
bother you with this again, but if you know something a bit closer to my
situation it would help me a lot.

As always, thanks for your help,

using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.Design;
using System.Web.UI.Design.WebControls;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Globalization;
using System.Drawing.Design;
using System.Diagnostics;
using System.Reflection;
using CompanyName.EEE.Web.UI;
using CompanyName.EEE.Web.UI.FormControls;

namespace CompanyName.EEE.Web.UI.WebBoxes
{
/// <summary>
/// This class provides an implementation of the <see cref="T:ITemplate"
/>
/// interface for allowing access to the <see cref="T:ITemplate" /> and
/// <see cref="T:EditableDesignerRegion" /> properties/methods in
/// <see cref="T:WebBox" /> controls.
/// </summary>
public class WebBoxTemplate : ITemplate
{
#region Constructor

/// <summary>
/// Initializes a new instance of the <see cref="WebBoxTemplate"/>
class.
/// </summary>
public WebBoxTemplate()
{
}

#endregion

#region Public Methods

/// <summary>
/// When implemented by a class, defines the <see cref="T:Control"
/> object
/// that child controls and templates belong to. These child
controls are
/// in turn defined within an inline template.
/// </summary>
/// <param name="container">The <see cref="T:Control" /> object to
contain
/// the instances of controls from the inline template.</param>
public void InstantiateIn(Control container)
{
// How to pass something at run-time to container.Controls ?
}

#endregion

}
}
 
S

Steven Cheng[MSFT]

Thanks for your response,

Yes, I know your confusion. Actually, what I used to think is that you want
to do what we do at design-time( add some controls into Template by editing
the Templte's inline markup in aspx file). As for ASP.NET control
template, at design-time it is persisted as markup string, at runtime, the
ASP.NET will call the template's InInstantiateIn method which will parse
and compile the template and build the template's control collection. Then,
those controls will be add into a container control's controls collection.

So one means to dynamically add additional controls into Template is define
custom template class, and we can completely programmatically create the
template at runtime and assign it to our custom control's Template field.

Also, another means is do something on the Container control, just like the
"ItemDataBound" or "RowDataBound" event of the DataGrid , GridView
control. Generally after calling template's InInstantiateIn, we'll add the
returned controls into a container control(such as the DataGridItem of
DataGrid). So in your custom control, you can consider use such a container
control to do the dynamic control adding or modifying.

Regards,

Steven Cheng
Microsoft Online Community Support


==================================================

When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.

==================================================


This posting is provided "AS IS" with no warranties, and confers no rights.



Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
C

Christophe Peillet

Steven:

I understood the need to override the InstantiateIn method ... what I
couldn't figure out is what code to put to be able to pass any number of
controls to this method at run time.

Would something like this work (I don't have VS in front of me to know the
exact signature of this method):

protected override void (?) InstantiateIn(ControlCollection controlsToAdd)
{
...
// And then add the contents of the passed ControlCollection into the
container?
}

My problem was handing the controls over to the InstantiateIn method ... I
just didn't see a good way to do this. If I can, I would like to avoid other
developers using my APIs or Framework from having to write 5 lines of code to
add a control to my ITemplate based property. Do you have any ideas or code
suggestions on how to do this in the InstantiateIn method?

As always, I appreciate your help and expertise on this.

Christophe
 
S

Steven Cheng[MSFT]

Thanks for your response Christophe,

I haven't found any particular resource on write our custom Template class
(override the InstantiateIn method). Also, I think you can consider the
other approach I mentioned, create a container class which hold the
controls intialized from the Template and we can throw some event (which
contains eventARgument reference to that container) so that the control's
user can use that event to customize the controls collection intialized
from Template. And in those ASP.NET built-in controls, you can have a look
at the Repeater control(also DataList) which use a container control (e.g
the Repeater's RepeaterItem ....). You can use the reflector tool to
inspect into its code, you'll find it create a RepeaterItem through the
CreateItem function and then call initializeItem which internally call the
template.InstantiateIn to parse the template controls, then raise some
events to let the user to customize the controls collection.

here is the reference code from reflector:

===========================
private RepeaterItem CreateItem(int itemIndex, ListItemType itemType, bool
dataBind, object dataItem)
{
RepeaterItem item1 = this.CreateItem(itemIndex, itemType);
RepeaterItemEventArgs args1 = new RepeaterItemEventArgs(item1);
this.InitializeItem(item1);
if (dataBind)
{
item1.DataItem = dataItem;
}
this.OnItemCreated(args1);
this.Controls.Add(item1);
if (dataBind)
{
item1.DataBind();
this.OnItemDataBound(args1);
item1.DataItem = null;
}
return item1;
}
============================

Hope this helps.

Regards,

Steven Cheng
Microsoft Online Community Support


==================================================

When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.

==================================================


This posting is provided "AS IS" with no warranties, and confers no rights.



Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
A

Alessandro Zifiglio

hi Christophe, Have you tried to add the information via the ToolboxData
Metadata attributes since these are applied to server controls (and to their
members) to provide information that is used by design tools, the ASP.NET
page parser, the ASP.NET run time, and the common language runtime.
Something like the following should work well for you :

[ToolboxData("<{0}:WebBox runat=\"server\">" +
"<Content>" +
" <div style=\"text-align: center\">" +
"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"
style=\"width: 100%\">" +
"<tr>" +
"<td> <CompanyUI:AdvancedTextBox ID=\"AdvancedTextBox1\"
runat=\"server\" LabelPosition=\"Bottom\"
Width=\"130px\"></CompanyUI:AdvancedTextBox></td>" +
"</tr>" +
"</table>" +
"</div>" +
"</Content>" +
"</{0}:WebBox>"),
Designer(typeof(SimpleContainerControlDesigner))]
public class WebBox : CompositeControl
{//definition for your webbox control}

When this control gets dropped in the page, the string passed to the
MetaData attribute ToolboxData is rendered into the page as as part of your
control, just as you want it. Atleast it seems to me this is what you are
trying to achieve.
This is just an example, but you get the idea. Have a good day.

Alessandro Zifiglio
 
A

Alessandro Zifiglio

oops, my mistake, now that i read your post (a bit slower this time) it
seems i have misread your post after all. The urls suggested by Steven Chen
are correct and the last post he made should answer your question.
My apologies :)
Regards,
Alessandro Zifiglio

Alessandro Zifiglio said:
hi Christophe, Have you tried to add the information via the ToolboxData
Metadata attributes since these are applied to server controls (and to
their members) to provide information that is used by design tools, the
ASP.NET page parser, the ASP.NET run time, and the common language
runtime. Something like the following should work well for you :

[ToolboxData("<{0}:WebBox runat=\"server\">" +
"<Content>" +
" <div style=\"text-align: center\">" +
"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"
style=\"width: 100%\">" +
"<tr>" +
"<td> <CompanyUI:AdvancedTextBox ID=\"AdvancedTextBox1\"
runat=\"server\" LabelPosition=\"Bottom\"
Width=\"130px\"></CompanyUI:AdvancedTextBox></td>" +
"</tr>" +
"</table>" +
"</div>" +
"</Content>" +
"</{0}:WebBox>"),
Designer(typeof(SimpleContainerControlDesigner))]
public class WebBox : CompositeControl
{//definition for your webbox control}

When this control gets dropped in the page, the string passed to the
MetaData attribute ToolboxData is rendered into the page as as part of
your control, just as you want it. Atleast it seems to me this is what you
are trying to achieve.
This is just an example, but you get the idea. Have a good day.

Alessandro Zifiglio

Christophe Peillet said:
I have a base custom control called 'WebBox' that contains a single
EditableDesignerRegion. The contents of this EditableDesignerRegion are
stored in an ITemplate via a property name 'Content', and serialized as
an
InnerProperty.

This all works as expected, renders properly, etc., but I can't figure
out
how, in a control that inherits WebBox (such as AdvertisementWebBox,
SearchWebBox, etc.) to add controls to the ITemplate in code on the
Server
Side. If I add things in the markup, as below, everything works fine
(see
inner property names 'Content').

<CompanyUI:WebBox ID="SearchWebBox" runat="server" IconWidth="0"
SkinID="SearchBox"
Title="Search" TitleVisible="True" Width="180px">
<Content>
<div style="text-align: center">
<table border="0" cellpadding="0" cellspacing="0"
style="width: 100%">
<tr>
<td align="left" style="width: 130px"
valign="top">
<CompanyUI:AdvancedTextBox
ID="AdvancedTextBox1"
runat="server" LabelPosition="Bottom"

Width="130px"></CompanyUI:AdvancedTextBox></td>
<td align="center" valign="top">
<CompanyUI:AdvancedButton ID="SearchButton"
runat="server" Text="go" /></td>
</tr>
<tr>
<td align="left" colspan="2" style="width: 130px"
valign="top">
<CompanyUI:CompanyHyperLink
ID="AdvancedSearchLink" runat="server" Description=""
LinkLeaderCssClass=""
LinkLeaderImageCssClass=""
LinkLeaderImageUrl="" NavigateUrl="~/AdvancedSearch.aspx"
TextResourceKey="AdvancedSearch">Advanced
Search</CompanyUI:CompanyHyperLink></td>
</tr>
</table>
</div>
</Content>
</CompanyUI:WebBox>

How can I do this in code in another specialized server control, though?

In the server control that inherits WebBox, I have tried the following,
but
with no success.

protected override void OnPreRender(EventArgs e)
{
// Call underlying OnPreRender method
base.OnPreRender(e);

if (!(this.DesignMode))
{
// Clear WebBox .Content control collection
Control template = new Control();
base.Content.InstantiateIn(template);

// ToDo: How to add controls to an ITemplate in code?

template.Controls.Clear();

... // Add controls to collection
... template.Controls.Add(...) ...
}
}

I want WebBox as a generic control with an empty ITemplate, and in
specialized controls that inherit from it to add controls like Search
boxes,
link listings, etc.

Any help on this would be appreciated.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top