AutoPostBack Interface - asp.net

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.

Related

ASP .NET Web Forms - Why is custom control's property setter not called by parent using data binding expression?

Why are my custom control's property setters not getting called by the parent page when using data binding expressions to set the control's properties? The setters are called when using a constant to set the control's properties.
MyPage.aspx:
...
<foo:MyControl ID="bar" runat="server" MyProperty="<%# Thirteen %>" />
...
MyPage.aspx.cs:
...
protected int Thirteen { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Thirteen = 13;
DataBind();
}
}
...
MyControl.ascx.cs:
public partial class MyControl : System.Web.UI.UserControl
{
public int MyProperty
{
get => (int)(ViewState["MyProperty"] ?? 0);
set => ViewState["MyProperty"] = value;
}
}
I set a breakpoint on the setter, and it's never called when I load the page.
However, if I change MyPage.aspx from/to this, it works:
<foo:MyControl ID="bar" runat="server" MyProperty="13" />
Is it possible to have the setter called using the data binding expression? What am I doing wrong?
Embarrassing...
My actual code for MyControl.ascx.cs was more appropriately the following:
public partial class MyControl : System.Web.UI.UserControl
{
public int MyProperty
{
get => (int)(ViewState["MyProperty"] ?? 0);
set => ViewState["MyProperty"] = value;
}
// THIS IS THE KEY
protected override void OnDataBinding(EventArgs e)
{
// bunch of stuff, but never calling base.OnDataBinding(e)
}
}
After adding base.OnDataBinding(e); to the overridden method, everything worked as expected.

ASP.NET customized asp:label view state

I created a new class for a project. The below is a very slightly simplified version.
public class CustomLabel : Label
{
public string ItemId { get; set; }
protected override void Render(HtmlTextWriter writer)
{
if (!Page.IsPostBack)
LoadText();
base.Render(writer);
}
protected void LoadText()
{
this.Text = "This is a test";
}
}
The problem I'm having is that the Text property is not lasting through postbacks. Even if I manually enable viewstate though the tag on the ascx page. Can the custom label tag not have viewstate? I would hate to have to load the text on every page load unnecessarily.
Move LoadText(); method call to OnPreRender method

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

ASP.NET ITemplate with TemplateInstance.Multiple

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.

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