ASP.NET ITemplate with TemplateInstance.Multiple - asp.net

I can't seem to find any examples on how to implement ITemplates with multiple instances. All I need to do is build out a navigation that has a template for the content of each navigation item.

If your control is not a databound control, you can solve the problem by something as follows. But, I haven't tested it.
public class FooItem : WebControl, INamingContainer
{
protected override CreateChildControls()
{
Control placeHolder = this.FindControl(((Foo)this.Parent).ItemPlaceHolderId);
if (placeHolder != null)
{
// Add some controls to the placeHolder.
}
}
}
public class Foo : WebControl, INamingContainer
{
public ITemplate ItemTemplate { get; set; }
public string ItemPlaceHolderId
{
get { ... }
set { ... }
}
public FooItemCollection Items
{
get { ... }
}
protected override CreateChildControls()
{
foreach (FooItem item in this.Items)
{
this.ItemTemplate.InstantiateIn(item);
}
}
}

Look at documentation of creating a data-bound templated control.
Unfortunately, the best documentation I've found is from .NET 1.1:
Developing a Templated Data-Bound Control.
Note from MSDN:
This TemplateInstanceAttribute class
is optional. If a template property is
not extended with a
TemplateInstanceAttribute class, the
default value, the Multiple field, is
used.
So any ITemplate example that does not use the TemplateInstanceAttribute is using TemplateInstance.Multiple.

Related

Custom server controls - how to get intellisense support and rid the xhtml error?

I have created a custom control which takes a custom template. But there is no intellisense support and there is this xhtml error.
I have checked some questions; this post says we have to get it by default. However I haven't been getting it. Am I missing something to do?
Here is how the code looks like:
Server Control:
[ToolboxData("<{0}:CustomTemplateControl runat=server></{0}:CustomTemplateControl>")]
[Description("My Custom Template Control")]
public class CustomTemplateControl : WebControl
{
[TemplateContainer(typeof(CustomTemplateItem))]
public ITemplate CustomHeader { get; set; }
protected override void CreateChildControls()
{
if (CustomHeader != null)
{
CustomHeader.InstantiateIn(this);
}
base.CreateChildControls();
}
public override void RenderBeginTag(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID);
writer.RenderBeginTag(HtmlTextWriterTag.Label);
//base.RenderBeginTag(writer);
}
Template:
public class CustomTemplateItem : Control, INamingContainer
{
}
You will have to create a schema file that describes your custom control and reference that schema file in whatever VS project. you use it in.
xhtml doesn't like uppercase characters. Probably would have to change the custom controls Attributes with all lowercase characters.

AutoPostBack Interface

I'm creating a set of Web User Controls which will share a common base class. The base will always contain a WebControl (either a Textbox, DropDownList, CheckBoxList, RadioButtonList, ListBox, and maybe others) and a RequiredFieldValidator. All is well, except that my abstract InputControl property (defined as type WebControl) doesn't seem to have the AutoPostBack property which I want them all to have (I assume this is because not all WebControls support AutoPostBack). I would love to put this functionality in completely in the base class and not have to define it in each child. It would look like:
public abstract WebControl InputControl { get; set; }
public bool AutoPostBack {
get { return InputControl.AutoPostBack; }
set { InputControl.AutoPostBack = value; }
}
But this obviously won't work because AutoPostBack is not a property of WebControl. Is there another interface that I could specify that would support this, or do I need to create my own?
autopostback is not in any base class because only some controls need autopostback property. what you can do is to use generics
public class MyBaseUC<T> : System.Web.UI.UserControl
{
public abstract T InputControl { get; set; }
}
public partial class WebUserControl1 : MyBaseUC<TextBox>
{
protected void Page_Load(object sender, EventArgs e)
{
InputControl.AutoPostBack = false;
}
}
Regards.

How can I define a property on an ASP.NET user or server control to allow multiple string values as nested tags with a custom tag name?

I need to write a user control that can be used with the following syntax:
<quiz:Question runat="server">
<Answer>Foo</Answer>
<Answer>Bar</Answer>
</quiz:Question>
I tried the following property declaration:
[ParseChildren(true, "Answer")]
public class Question : UserControl
{
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public string[] Answer { get; set; }
}
But then the Visual Studio editor insist that <Answers > should be self-closing and I get this exception if I decide otherwise:
Literal content ('Foo') is not allowed within a 'System.String[]'.
I have been looking at <asp:DropDownList> in Reflector, which inherits from ListControl which declares the Items property as follows:
ParseChildren(true, "Items")
public abstract class ListControl
{
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public virtual ListItemCollection Items { get; }
}
It's not really the same as what I want, because in DropDownList you must add <asp:ListItem> as children. And there are some things I don't understand about control design, which is currently preventing me from finding the solution:
Why doesn't the <asp:ListItem> tag require a runat="server" attribute?
Can I declare such a 'control'?
What's so special about the ListItemCollection that it translates to this particular syntax?
What code can I write that will translate to the syntax given in the first code example above?
I mixed behavior of controls those can have child items (like ListControl), with controls like Panel (ParseChildren=false) :
[ParseChildren(true, "Answers")]
public class Question : WebControl, INamingContainer
{
private AnswerCollection answers;
public virtual AnswerCollection Answers
{
get
{
if (this.answers == null)
{
this.answers = new AnswerCollection();
}
return this.answers;
}
}
public override void RenderControl(HtmlTextWriter writer)
{
//access to each answer value
foreach (var a in this.Answers)
writer.WriteLine(((LiteralControl)a.Controls[0]).Text + "<br/>");
}
}
[ParseChildren(false), PersistChildren(true)]
public class Answer : Control
{
}
public class AnswerCollection : List<Answer>
{
}
Then you would be able to have something like :
<cc1:Question runat="server">
<cc1:Answer>Answer1</cc1:Answer>
<cc1:Answer>Answer2</cc1:Answer>
</cc1:Question>
Hope it helps

Call Public Property Declared in a ASPX Page from a Different ASPX Page

How can I call a public property declared on a ASPX page from a different ASPX Page? Is that possible? It is a website project. How can I get/call this property from a different aspx page? I have attempted this from the other page, but it is not recognizing the partial class: private Test_Default _test; It does not recognize the "Test_Default"
I.E.
public partial class Test_Default : System.Web.UI.Page
{
private string myAge = string.empty;
public string Name
{
get
{
return myName;
}
set
{
myName = value;
}
}
If you need a piece of shared code, create a class for it in the APP_CODE folder.
See MSDN documentation here and here.
I would create a separate class exposing the property you are wanting to work with, and store the value in Session :
public class MyClass
{
public static string MyName
{
get
{
if (Session["MY_NAME"] != null)
{
return Session["MY_NAME"].ToString();
}
return String.Empty;
}
set { Session["MY_NAME"] = value; }
}
}
You should be able to call that from either Page. If it's a complex object, then change the type from string to your object.
Hope that helps!!

ASP.NET Templated Control

I'm attempting to build a templated control. You'll see that as part of the Field section, I'd like to be able to define controls as children. When I attempt to compile I'm receiving the error message "MyTemplateControl.Field' does not have a public property named 'Button'". Does anyone know how to accomplish what I'm trying to do?
Below you'll find an example XHTML markup, and below that my control implementation.
I've editted my example to hopefully clarify what I'm looking for. Thanks everyone for the MSDN links. I've been through those already.
What I'm trying to build is a data entry control that will auto format a table for me. We do a lot of data entry webforms, and I'd like to ease the implementation time.
<cc1:MyForm ID="MyForm1" runat="server">
<ViewTemplate>
<cc1:Field Question="What is your name?">
<asp:Label ID="myLabel" runat="server" />
</cc1:Field>
</ViewTemplate>
<EditTemplate>
<cc1:Field Question="What is your name?">
<asp:Textbox ID="myTextbox" runat="server" />
</cc1:Field>
</EditTemplate>
</cc1:MyForm>
public class MyForm : WebControl, INamingContainer
{
private FieldCollection _fieldCollection;
private FieldCollection _field2Collection;
public FieldCollection ViewTemplate
{
get
{
if (_fieldCollection == null)
{
_fieldCollection = new FieldCollection();
}
return _fieldCollection;
}
}
public FieldCollection EditTemplate
{
get
{
if (_field2Collection == null)
{
_field2Collection = new FieldCollection();
}
return _field2Collection;
}
}
}
public class FieldCollection : CollectionBase
{
.
.
.
}
[ParseChildren(false)]
public class Field
{
.
.
.
}
There's something strange in your implementation. It's difficult to understand what you'd like to do, either to build a templated control, or a control on which you can add a list of child controls.
For the templated approach you'd have to do something like this:
public class MyForm : WebControl, INamingContainer
{
private TemplateOwner templateOwner{ get; set; }
private ITemplate _Content;
public ITemplate Content
{
get
{
return this._Content;
}
set
{
_Content = value;
}
}
protected override void CreateChildControls()
{
base.Controls.Clear();
templateOwner = new TemplateOwner();
this.Content.InstantiateIn(templateOwner);
this.Controls.Add(templateOwner);
}
...
}
[ToolboxItem(false)]
public class TemplateOwner : WebControl{
public TemplateOwner():base(HtmlTextWriterTag.Div)
{
}
}
The usage would then look like
<cc1:MyForm ID="MyForm1" runat="server">
<Content>
<!-- Place whatever HTML, ASP.net controls etc you like -->
</Content>
</cc1:MyForm>
You still have to add the appropriate annotations to configure the behavior of the designer. I just wrote this down quickly to give you an idea.
GridView also doesn't allow such manipulation,
Instead use MyForm1.FindControl("mybutton")
Also I have notice your template is not derived from ITemplate interface. As usual ASP.Net also uses System.Web.UI.Control as base class for this impl.
I used the following code:
public partial class SmallFramedControl : UserControl, INamingContainer
{
private TemplateOwner templateOwner { get; set; }
private ITemplate _Content;
public ITemplate Content
{
get
{
return this._Content;
}
set
{
_Content = value;
}
}
protected override void CreateChildControls()
{
//base.Controls.Clear();
templateOwner = new TemplateOwner();
this.Content.InstantiateIn(templateOwner);
plchAdd.Controls.Add(templateOwner);
}
protected void Page_Load(object sender, EventArgs e)
{
}
}
[ToolboxItem(false)]
public class TemplateOwner : WebControl
{
public TemplateOwner()
: base(HtmlTextWriterTag.Div)
{
}
}
and ascx page look like:
<%# Control Language="C#" AutoEventWireup="true"
CodeBehind="SmallFramedControl.ascx.cs"
Inherits="OtPortalNewDesign.UserControls.SmallFramedControl" %>
this will be top of frame
<asp:PlaceHolder ID="plchAdd" runat="server"></asp:PlaceHolder>
this will be bottom of frame

Resources