Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > ASP .Net > ASP .Net Building Controls > Problem overriding render method to format literal content of nested tags in custom control

Reply
Thread Tools

Problem overriding render method to format literal content of nested tags in custom control

 
 
Stephen Miller
Guest
Posts: n/a
 
      01-03-2004
Gurus,

I have a custom web control that in turn has nested child controls. I
want to be able to encapsulated and render any literal HTML and or
server controls placed between the child control's tags. This works
fine, unless I add a RequiredFieldValidator control at which point my
aspx page fails at 'WebControls.BaseValidator.CheckControlValidationP roperty'
with the error message 'Unable to find control id 'TextBox1'
referenced by the 'ControlToValidate' property of
'RequiredFieldValidator1'.

My control 'Nested' contains a collection of 'NestedChild' controls
with a simple 'Caption' property. I override the 'Render' method on
the 'Nested' control and iterate though each NestedChild' in the
collection, outputting the child's literal content to a formatted
table.

The full code for my control is (please cut-n-paste to replicate my
problem):

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Collections;
using System.Collections.Specialized;
using System.Web.UI.HtmlControls;

namespace Custom.Web.UI {

[ToolboxData("<{0}:Nested runat=server></{0}:Nested2>")]
[ParseChildren(true, "NestedChild"), PersistChildren(false)]
public class Nested : WebControl, INamingContainer,
IPostBackDataHandler {

private NestedChildCollection _NestedChildren = new
NestedChildCollection();

#region Properties
[
DesignerSerializationVisibility(DesignerSerializat ionVisibility.Content),
PersistenceMode(PersistenceMode.InnerDefaultProper ty),
Description("A collection of nested children"),
]
public NestedChildCollection NestedChild {
get{ return _NestedChildren; }
}
#endregion

#region Overrides

protected override void CreateChildControls() {
this.Controls.Clear();
foreach (NestedChild child in _NestedChildren) {
this.Controls.Add(child);
}
}

protected override void Render(HtmlTextWriter output) {
output.Write("<b>before</b><br /><hr><br />");
//base.Render(output);
foreach(NestedChild child in _NestedChildren) {
output.Write("* " + child.Caption + "<BR>");

// Display the literal contents of NestedChild
// in a single table cell
HtmlTableCell td = new HtmlTableCell();
td.Controls.Add(child);

// Add the table cell to a new table row
HtmlTableRow tr = new HtmlTableRow();
tr.Controls.Add(td);

// Add the table row to a new table
HtmlTable table = new HtmlTable();
table.ID = this.UniqueID;
table.CellSpacing = 2;
table.CellPadding = 2;
table.Border = 1;
table.Style.Add("background-color", "#C0C0C0");
table.Controls.Add(tr);

/* FAILS NEXT LINE
Error: "Unable to find control id 'txtTest1' referenced
by the 'ControlToValidate' property of 'valTest1'"
/*
table.RenderControl(output);
}
output.Write("<br /><hr><br /><b>after</b>");
}
#endregion

#region Implements IPostBackDataHandler (postback only)
bool IPostBackDataHandler.LoadPostData(string strPostDataKey,
NameValueCollection postDataCollection) {
return true;
}
void IPostBackDataHandler.RaisePostDataChangedEvent() {}
#endregion
}

[ToolboxItem(false), DefaultProperty("Caption")]
public class NestedChild : Control{
private String m_strCaption;
public String Caption {
get { return m_strCaption; }
set { m_strCaption = value; }
}
}

public class NestedChildCollection : CollectionBase {

public NestedChild this[int nIndex]{
get { return (NestedChild) base.List[nIndex]; }
}
public void Add(NestedChild child){
base.List.Add(child);
}

public int IndexOf(NestedChild child){
return base.List.IndexOf(child);
}
}
}

When deployed the aspx page looks like:

<form id="Form1" method="post" runat="server">
<P>Nested Control</P>
<P>
<cc1:Nested id="Nested1" runat="server">
<cc1:NestedChild Caption="NestedChild">
<asp:Button id="cmdTest" runat="server" Text="Generate
Event"></asp:Button>
<asp:TextBox id="txtTest" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator id="valTest" runat="server"
ControlToValidate="txtTest"
ErrorMessage="This field is
Required.">*</asp:RequiredFieldValidator>
</cc1:NestedChild>
</cc1:Nested2></P>
<P>&nbsp;</P>
<P>
<asp:label id="lblResult" runat="server">lblResult</asp:label></P>
</form>

If I remove 'RequiredFieldValidator' my control render as expected.

I have noticed, that If I replace the entire formatting logic in the
'Render' method with a call to 'base.Render(output);', the
RequiredFieldValidator works as expected.

I think this is quite a technical problem and I assume that
'table.RenderControl(output)' is not preforming the necessary
server-side pre-validation to pass a 'RequiredFieldValidator'. How can
I do this?

Regards,

Stephen
 
Reply With Quote
 
 
 
 
Stephen Miller
Guest
Posts: n/a
 
      01-04-2004
Peter,

Thanks for the link. I have enjoyed looking at your site, but its not
going to give me the answer I need. My control needs to be able to
render any nested literal content the developer throws at it, so I
have to resolve this problem with MS's validators.

I have designed my control in such a way that it only needs to
validate controls in the same naming container but as you noted, the
error message seems to indicate that the control thinks the textbox
and validator are in different containers.

What I find particularly puzzling is that if I simple override the
render method with 'base.Render(output)' the validator has not problem
locating the textbox in the container. The problem only seems to arise
when I attempt to encapsulate the controls in my own formatting with
'table.RenderControl(output)'.

Should I be looking at overriding the 'table.RenderControl' method to
make this work? If so what should I be doing?

I recently found another commercial product that is able to do what
I'm trying to achive
(http://www.infragistics.com/products...sp?sec=0&cat=3) so I
know it must be possible (... and I don't want to pay USD $500)

Thanks,

Stephen



"Peter Blum" <(E-Mail Removed)> wrote in message news:<O#(E-Mail Removed)>...
> The ControlToValidate property only accepts the ID of another control in the
> same naming container. I believe that this error is due to naming container
> problems. While your code seems to enclose both the textbox and validator
> within the same naming container, the error message says otherwise.
>
> FYI: If the naming container is indeed the problem, I have a commercial
> product that replaces Microsoft's validators to overcome its many
> limitations. My validators support controls in any naming container. The
> product is "Professional Validation And More". Details are at
> http://www.peterblum.com/vam/home.aspx.
>
> --- Peter Blum
> www.PeterBlum.com
> Email: http://www.velocityreviews.com/forums/(E-Mail Removed)
>
> "Stephen Miller" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed) om...
> > Gurus,
> >
> > I have a custom web control that in turn has nested child controls. I
> > want to be able to encapsulated and render any literal HTML and or
> > server controls placed between the child control's tags. This works
> > fine, unless I add a RequiredFieldValidator control at which point my
> > aspx page fails at

> 'WebControls.BaseValidator.CheckControlValidationP roperty'
> > with the error message 'Unable to find control id 'TextBox1'
> > referenced by the 'ControlToValidate' property of
> > 'RequiredFieldValidator1'.
> >
> > My control 'Nested' contains a collection of 'NestedChild' controls
> > with a simple 'Caption' property. I override the 'Render' method on
> > the 'Nested' control and iterate though each NestedChild' in the
> > collection, outputting the child's literal content to a formatted
> > table.
> >
> > The full code for my control is (please cut-n-paste to replicate my
> > problem):
> >
> > using System;
> > using System.Web.UI;
> > using System.Web.UI.WebControls;
> > using System.ComponentModel;
> > using System.Collections;
> > using System.Collections.Specialized;
> > using System.Web.UI.HtmlControls;
> >
> > namespace Custom.Web.UI {
> >
> > [ToolboxData("<{0}:Nested runat=server></{0}:Nested2>")]
> > [ParseChildren(true, "NestedChild"), PersistChildren(false)]
> > public class Nested : WebControl, INamingContainer,
> > IPostBackDataHandler {
> >
> > private NestedChildCollection _NestedChildren = new
> > NestedChildCollection();
> >
> > #region Properties
> > [
> >

> DesignerSerializationVisibility(DesignerSerializat ionVisibility.Content),
> > PersistenceMode(PersistenceMode.InnerDefaultProper ty),
> > Description("A collection of nested children"),
> > ]
> > public NestedChildCollection NestedChild {
> > get{ return _NestedChildren; }
> > }
> > #endregion
> >
> > #region Overrides
> >
> > protected override void CreateChildControls() {
> > this.Controls.Clear();
> > foreach (NestedChild child in _NestedChildren) {
> > this.Controls.Add(child);
> > }
> > }
> >
> > protected override void Render(HtmlTextWriter output) {
> > output.Write("<b>before</b><br /><hr><br />");
> > //base.Render(output);
> > foreach(NestedChild child in _NestedChildren) {
> > output.Write("* " + child.Caption + "<BR>");
> >
> > // Display the literal contents of NestedChild
> > // in a single table cell
> > HtmlTableCell td = new HtmlTableCell();
> > td.Controls.Add(child);
> >
> > // Add the table cell to a new table row
> > HtmlTableRow tr = new HtmlTableRow();
> > tr.Controls.Add(td);
> >
> > // Add the table row to a new table
> > HtmlTable table = new HtmlTable();
> > table.ID = this.UniqueID;
> > table.CellSpacing = 2;
> > table.CellPadding = 2;
> > table.Border = 1;
> > table.Style.Add("background-color", "#C0C0C0");
> > table.Controls.Add(tr);
> >
> > /* FAILS NEXT LINE
> > Error: "Unable to find control id 'txtTest1' referenced
> > by the 'ControlToValidate' property of 'valTest1'"
> > /*
> > table.RenderControl(output);
> > }
> > output.Write("<br /><hr><br /><b>after</b>");
> > }
> > #endregion
> >
> > #region Implements IPostBackDataHandler (postback only)
> > bool IPostBackDataHandler.LoadPostData(string strPostDataKey,
> > NameValueCollection postDataCollection) {
> > return true;
> > }
> > void IPostBackDataHandler.RaisePostDataChangedEvent() {}
> > #endregion
> > }
> >
> > [ToolboxItem(false), DefaultProperty("Caption")]
> > public class NestedChild : Control{
> > private String m_strCaption;
> > public String Caption {
> > get { return m_strCaption; }
> > set { m_strCaption = value; }
> > }
> > }
> >
> > public class NestedChildCollection : CollectionBase {
> >
> > public NestedChild this[int nIndex]{
> > get { return (NestedChild) base.List[nIndex]; }
> > }
> > public void Add(NestedChild child){
> > base.List.Add(child);
> > }
> >
> > public int IndexOf(NestedChild child){
> > return base.List.IndexOf(child);
> > }
> > }
> > }
> >
> > When deployed the aspx page looks like:
> >
> > <form id="Form1" method="post" runat="server">
> > <P>Nested Control</P>
> > <P>
> > <cc1:Nested id="Nested1" runat="server">
> > <cc1:NestedChild Caption="NestedChild">
> > <asp:Button id="cmdTest" runat="server" Text="Generate
> > Event"></asp:Button>
> > <asp:TextBox id="txtTest" runat="server"></asp:TextBox>
> > <asp:RequiredFieldValidator id="valTest" runat="server"
> > ControlToValidate="txtTest"
> > ErrorMessage="This field is
> > Required.">*</asp:RequiredFieldValidator>
> > </cc1:NestedChild>
> > </cc1:Nested2></P>
> > <P>&nbsp;</P>
> > <P>
> > <asp:label id="lblResult" runat="server">lblResult</asp:label></P>
> > </form>
> >
> > If I remove 'RequiredFieldValidator' my control render as expected.
> >
> > I have noticed, that If I replace the entire formatting logic in the
> > 'Render' method with a call to 'base.Render(output);', the
> > RequiredFieldValidator works as expected.
> >
> > I think this is quite a technical problem and I assume that
> > 'table.RenderControl(output)' is not preforming the necessary
> > server-side pre-validation to pass a 'RequiredFieldValidator'. How can
> > I do this?
> >
> > Regards,
> >
> > Stephen

 
Reply With Quote
 
 
 
 
Stephen Miller
Guest
Posts: n/a
 
      01-07-2004
Peter,

I was under the mistaken impression that I was already overriding
CreateChildControls to create the controls with the code:

protected override void CreateChildControls() {
this.Controls.Clear();
foreach (NestedChild child in _NestedChildren) {
this.Controls.Add(child);
}
}

If I leave this override out then the control renders fine (with the
RequiredFieldValidators) but fails to generate any server side events.
Moving this code block to OnPreRender (with base.OnPreRend) after
adding the controls doesn't seem to make any difference.

I have also tried moving the code in the overridden Render method to
the overridden RenderContents method. This doesn't appear to have made
any difference.

Have I missed the point? Could I beg you for some sample code?

Thanks,

Stephen

"Peter Blum" <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...
> I think I see the problem. You are creating your control objects in the
> Render method. Leave the Render method alone. Generally, only use it if you
> wanted to output explicit HTML (although there are some cases where you can
> do what you did.) Instead, create the controls in either the
> CreateChildControls() or OnPreRender method.
>
> Here's the actual problem you are having. Validators must have their
> OnPreRender method run. Because your validators aren't in this control's
> Controls property, they don't get OnPreRender run. So move your code to
> OnPreRender and call base.OnPreRender() after those controls are added to
> the Controls property.
>
> --- Peter Blum
> www.PeterBlum.com
> Email: (E-Mail Removed)
>
> "Stephen Miller" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed) om...
> > Peter,
> >
> > Thanks for the link. I have enjoyed looking at your site, but its not
> > going to give me the answer I need. My control needs to be able to
> > render any nested literal content the developer throws at it, so I
> > have to resolve this problem with MS's validators.
> >
> > I have designed my control in such a way that it only needs to
> > validate controls in the same naming container but as you noted, the
> > error message seems to indicate that the control thinks the textbox
> > and validator are in different containers.
> >
> > What I find particularly puzzling is that if I simple override the
> > render method with 'base.Render(output)' the validator has not problem
> > locating the textbox in the container. The problem only seems to arise
> > when I attempt to encapsulate the controls in my own formatting with
> > 'table.RenderControl(output)'.
> >
> > Should I be looking at overriding the 'table.RenderControl' method to
> > make this work? If so what should I be doing?
> >
> > I recently found another commercial product that is able to do what
> > I'm trying to achive
> > (http://www.infragistics.com/products...sp?sec=0&cat=3) so I
> > know it must be possible (... and I don't want to pay USD $500)
> >
> > Thanks,
> >
> > Stephen
> >
> >
> >
> > "Peter Blum" <(E-Mail Removed)> wrote in message

> news:<O#(E-Mail Removed)>...
> > > The ControlToValidate property only accepts the ID of another control in

> the
> > > same naming container. I believe that this error is due to naming

> container
> > > problems. While your code seems to enclose both the textbox and

> validator
> > > within the same naming container, the error message says otherwise.
> > >
> > > FYI: If the naming container is indeed the problem, I have a commercial
> > > product that replaces Microsoft's validators to overcome its many
> > > limitations. My validators support controls in any naming container. The
> > > product is "Professional Validation And More". Details are at
> > > http://www.peterblum.com/vam/home.aspx.
> > >
> > > --- Peter Blum
> > > www.PeterBlum.com
> > > Email: (E-Mail Removed)
> > >
> > > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > > news:(E-Mail Removed) om...
> > > > Gurus,
> > > >
> > > > I have a custom web control that in turn has nested child controls. I
> > > > want to be able to encapsulated and render any literal HTML and or
> > > > server controls placed between the child control's tags. This works
> > > > fine, unless I add a RequiredFieldValidator control at which point my
> > > > aspx page fails at

> 'WebControls.BaseValidator.CheckControlValidationP roperty'
> > > > with the error message 'Unable to find control id 'TextBox1'
> > > > referenced by the 'ControlToValidate' property of
> > > > 'RequiredFieldValidator1'.
> > > >
> > > > My control 'Nested' contains a collection of 'NestedChild' controls
> > > > with a simple 'Caption' property. I override the 'Render' method on
> > > > the 'Nested' control and iterate though each NestedChild' in the
> > > > collection, outputting the child's literal content to a formatted
> > > > table.
> > > >
> > > > The full code for my control is (please cut-n-paste to replicate my
> > > > problem):
> > > >
> > > > using System;
> > > > using System.Web.UI;
> > > > using System.Web.UI.WebControls;
> > > > using System.ComponentModel;
> > > > using System.Collections;
> > > > using System.Collections.Specialized;
> > > > using System.Web.UI.HtmlControls;
> > > >
> > > > namespace Custom.Web.UI {
> > > >
> > > > [ToolboxData("<{0}:Nested runat=server></{0}:Nested2>")]
> > > > [ParseChildren(true, "NestedChild"), PersistChildren(false)]
> > > > public class Nested : WebControl, INamingContainer,
> > > > IPostBackDataHandler {
> > > >
> > > > private NestedChildCollection _NestedChildren = new
> > > > NestedChildCollection();
> > > >
> > > > #region Properties
> > > > [
> > > >
> > >

> DesignerSerializationVisibility(DesignerSerializat ionVisibility.Content),
> > > > PersistenceMode(PersistenceMode.InnerDefaultProper ty),
> > > > Description("A collection of nested children"),
> > > > ]
> > > > public NestedChildCollection NestedChild {
> > > > get{ return _NestedChildren; }
> > > > }
> > > > #endregion
> > > >
> > > > #region Overrides
> > > >
> > > > protected override void CreateChildControls() {
> > > > this.Controls.Clear();
> > > > foreach (NestedChild child in _NestedChildren) {
> > > > this.Controls.Add(child);
> > > > }
> > > > }
> > > >
> > > > protected override void Render(HtmlTextWriter output) {
> > > > output.Write("<b>before</b><br /><hr><br />");
> > > > //base.Render(output);
> > > > foreach(NestedChild child in _NestedChildren) {
> > > > output.Write("* " + child.Caption + "<BR>");
> > > >
> > > > // Display the literal contents of NestedChild
> > > > // in a single table cell
> > > > HtmlTableCell td = new HtmlTableCell();
> > > > td.Controls.Add(child);
> > > >
> > > > // Add the table cell to a new table row
> > > > HtmlTableRow tr = new HtmlTableRow();
> > > > tr.Controls.Add(td);
> > > >
> > > > // Add the table row to a new table
> > > > HtmlTable table = new HtmlTable();
> > > > table.ID = this.UniqueID;
> > > > table.CellSpacing = 2;
> > > > table.CellPadding = 2;
> > > > table.Border = 1;
> > > > table.Style.Add("background-color", "#C0C0C0");
> > > > table.Controls.Add(tr);
> > > >
> > > > /* FAILS NEXT LINE
> > > > Error: "Unable to find control id 'txtTest1' referenced
> > > > by the 'ControlToValidate' property of 'valTest1'"
> > > > /*
> > > > table.RenderControl(output);
> > > > }
> > > > output.Write("<br /><hr><br /><b>after</b>");
> > > > }
> > > > #endregion
> > > >
> > > > #region Implements IPostBackDataHandler (postback only)
> > > > bool IPostBackDataHandler.LoadPostData(string strPostDataKey,
> > > > NameValueCollection postDataCollection) {
> > > > return true;
> > > > }
> > > > void IPostBackDataHandler.RaisePostDataChangedEvent() {}
> > > > #endregion
> > > > }
> > > >
> > > > [ToolboxItem(false), DefaultProperty("Caption")]
> > > > public class NestedChild : Control{
> > > > private String m_strCaption;
> > > > public String Caption {
> > > > get { return m_strCaption; }
> > > > set { m_strCaption = value; }
> > > > }
> > > > }
> > > >
> > > > public class NestedChildCollection : CollectionBase {
> > > >
> > > > public NestedChild this[int nIndex]{
> > > > get { return (NestedChild) base.List[nIndex]; }
> > > > }
> > > > public void Add(NestedChild child){
> > > > base.List.Add(child);
> > > > }
> > > >
> > > > public int IndexOf(NestedChild child){
> > > > return base.List.IndexOf(child);
> > > > }
> > > > }
> > > > }
> > > >
> > > > When deployed the aspx page looks like:
> > > >
> > > > <form id="Form1" method="post" runat="server">
> > > > <P>Nested Control</P>
> > > > <P>
> > > > <cc1:Nested id="Nested1" runat="server">
> > > > <cc1:NestedChild Caption="NestedChild">
> > > > <asp:Button id="cmdTest" runat="server" Text="Generate
> > > > Event"></asp:Button>
> > > > <asp:TextBox id="txtTest" runat="server"></asp:TextBox>
> > > > <asp:RequiredFieldValidator id="valTest" runat="server"
> > > > ControlToValidate="txtTest"
> > > > ErrorMessage="This field is
> > > > Required.">*</asp:RequiredFieldValidator>
> > > > </cc1:NestedChild>
> > > > </cc1:Nested2></P>
> > > > <P>&nbsp;</P>
> > > > <P>
> > > > <asp:label id="lblResult" runat="server">lblResult</asp:label></P>
> > > > </form>
> > > >
> > > > If I remove 'RequiredFieldValidator' my control render as expected.
> > > >
> > > > I have noticed, that If I replace the entire formatting logic in the
> > > > 'Render' method with a call to 'base.Render(output);', the
> > > > RequiredFieldValidator works as expected.
> > > >
> > > > I think this is quite a technical problem and I assume that
> > > > 'table.RenderControl(output)' is not preforming the necessary
> > > > server-side pre-validation to pass a 'RequiredFieldValidator'. How can
> > > > I do this?
> > > >
> > > > Regards,
> > > >
> > > > Stephen

 
Reply With Quote
 
Stephen Miller
Guest
Posts: n/a
 
      01-11-2004
Peter,

Again, thanks for your on going help.

I have been struggling with this problem for 3+ months and on someone
else's advice purchased "Developing Microsoft ASP.NET Server Controls
and Components". Following the book religiously, I started again from
the "Hello World" example and worked forward to recreate my problem.
Kothari & Datye's touches on controls "whose nested content does not
correspond to properties" on pages 332-7, but the example provided is
very trivial and doesn't address any of the issues I've encountered.
If I've missed something, please point me to the section.

My control uses the ParseChildrenAttribute attribute with the
declaration '[ParseChildren(true, "NestedChild")', which defines a
public property named 'NestedChild', with nested (child) elements
corresponding to child elements of the 'NestedChild' property. The
idea with the '_NestedChildren' property is to add each nested child
element to a collection, which I can iterate through and hide or show
based on additional conditions. I have extra logic here, which I have
omitted for clarity.

As you suggested, I have move my code to CreateChildControls. The
control renders ok in design time, but fails in runtime at
FillNamedControlsTable with the error message "Multiple controls with
the same ID 'myControl1' were found. FindControl requires that
controls have unique IDs". With the RequiredFieldValidator removed,
the control renders but generates the same error with the buttons
onClick event. Looking at the source code I notice that the command
button has now rendered as:

<input type="submit" name="myControl1:cmdTest1" value="Test"
id="myControl1_cmdTest1" />

I can't compile my code behind with an event handling
myControl1_cmdTest1.Click, because the compiler is expecting
cmdTest1.click.

My code for CreateChildControls now looks like:

protected override void CreateChildControls() {

this.Controls.Clear();
this.Controls.Add(new LiteralControl("<b>before</b><br /><hr><br
/>"));

foreach (NestedChild child in _NestedChildren) {
//this.Controls.Add(child);

this.Controls.Add(new LiteralControl("* " + child.Caption +
"<BR>"));

// Display the contents of child in a single cell table
HtmlTableCell td = new HtmlTableCell();
td.Style.Add("width", "250px");
td.Style.Add("height", "100px");
td.Controls.Add(child);

// Add the table cell to a new table row
HtmlTableRow tr = new HtmlTableRow();
tr.Controls.Add(td);

// Add the table row to a new table
HtmlTable table = new HtmlTable();
table.ID = this.UniqueID;
table.Width = this.Width.ToString();
table.Height = this.Height.ToString();
table.CellSpacing = 2;
table.CellPadding = 2;
table.Border = 1;
table.Style.Add("background-color", "#C0C0C0");
table.Controls.Add(tr);

this.Controls.Add(table);

}
this.Controls.Add(new LiteralControl("<br /><hr><br
/><b>after</b>"));
}

Any other suggestions?

Regards,

Stephen


"Peter Blum" <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...
> I strongly encourage you to step back and learn the right way to build
> custom controls. Otherwise, you will be developing code that may require
> plenty more debugging and maintenance because it doesn't confirm to how
> Microsoft designed web controls. I recommend the book "Developing ASP.NET
> Server Controls and Components" from Microsoft Press.
>
> In your code, I do not understand why you have the _NestedChildren property.
> The webcontrol framework automatically supports child controls using the
> ParseChildrenAttribute. (See the .net docs on this attribute.) I do
> understand what you are doing in CreateChildControls and that looks OK.
>
> Here are my recommendations.
> - Move the code you have creating the table and its contents into
> CreateChildControls without removing the existing code.
> - Any "output.Write()" calls can become LiteralControl objects. (new
> LiteralControl("<br>"))
> - Add objects to the Controls collection on your control.
>
> Now your validators will be created before OnPreRender occurs. That allows
> the webcontrol system that Microsoft designed to call each of your
> validators own OnPreRender method properly, setting up many things that are
> required for validation.
>
> --- Peter Blum
> www.PeterBlum.com
> Email: (E-Mail Removed)
> "Stephen Miller" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed) m...
> > Peter,
> >
> > I was under the mistaken impression that I was already overriding
> > CreateChildControls to create the controls with the code:
> >
> > protected override void CreateChildControls() {
> > this.Controls.Clear();
> > foreach (NestedChild child in _NestedChildren) {
> > this.Controls.Add(child);
> > }
> > }
> >
> > If I leave this override out then the control renders fine (with the
> > RequiredFieldValidators) but fails to generate any server side events.
> > Moving this code block to OnPreRender (with base.OnPreRend) after
> > adding the controls doesn't seem to make any difference.
> >
> > I have also tried moving the code in the overridden Render method to
> > the overridden RenderContents method. This doesn't appear to have made
> > any difference.
> >
> > Have I missed the point? Could I beg you for some sample code?
> >
> > Thanks,
> >
> > Stephen
> >
> > "Peter Blum" <(E-Mail Removed)> wrote in message

> news:<(E-Mail Removed)>...
> > > I think I see the problem. You are creating your control objects in the
> > > Render method. Leave the Render method alone. Generally, only use it if

> you
> > > wanted to output explicit HTML (although there are some cases where you

> can
> > > do what you did.) Instead, create the controls in either the
> > > CreateChildControls() or OnPreRender method.
> > >
> > > Here's the actual problem you are having. Validators must have their
> > > OnPreRender method run. Because your validators aren't in this control's
> > > Controls property, they don't get OnPreRender run. So move your code to
> > > OnPreRender and call base.OnPreRender() after those controls are added

> to
> > > the Controls property.
> > >
> > > --- Peter Blum
> > > www.PeterBlum.com
> > > Email: (E-Mail Removed)
> > >
> > > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > > news:(E-Mail Removed) om...
> > > > Peter,
> > > >
> > > > Thanks for the link. I have enjoyed looking at your site, but its not
> > > > going to give me the answer I need. My control needs to be able to
> > > > render any nested literal content the developer throws at it, so I
> > > > have to resolve this problem with MS's validators.
> > > >
> > > > I have designed my control in such a way that it only needs to
> > > > validate controls in the same naming container but as you noted, the
> > > > error message seems to indicate that the control thinks the textbox
> > > > and validator are in different containers.
> > > >
> > > > What I find particularly puzzling is that if I simple override the
> > > > render method with 'base.Render(output)' the validator has not problem
> > > > locating the textbox in the container. The problem only seems to arise
> > > > when I attempt to encapsulate the controls in my own formatting with
> > > > 'table.RenderControl(output)'.
> > > >
> > > > Should I be looking at overriding the 'table.RenderControl' method to
> > > > make this work? If so what should I be doing?
> > > >
> > > > I recently found another commercial product that is able to do what
> > > > I'm trying to achive
> > > > (http://www.infragistics.com/products...sp?sec=0&cat=3) so I
> > > > know it must be possible (... and I don't want to pay USD $500)
> > > >
> > > > Thanks,
> > > >
> > > > Stephen
> > > >
> > > >
> > > >
> > > > "Peter Blum" <(E-Mail Removed)> wrote in message

> news:<O#(E-Mail Removed)>...
> > > > > The ControlToValidate property only accepts the ID of another

> control in
> the
> > > > > same naming container. I believe that this error is due to naming

> container
> > > > > problems. While your code seems to enclose both the textbox and

> validator
> > > > > within the same naming container, the error message says otherwise.
> > > > >
> > > > > FYI: If the naming container is indeed the problem, I have a

> commercial
> > > > > product that replaces Microsoft's validators to overcome its many
> > > > > limitations. My validators support controls in any naming container.

> The
> > > > > product is "Professional Validation And More". Details are at
> > > > > http://www.peterblum.com/vam/home.aspx.
> > > > >
> > > > > --- Peter Blum
> > > > > www.PeterBlum.com
> > > > > Email: (E-Mail Removed)
> > > > >
> > > > > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > > > > news:(E-Mail Removed) om...
> > > > > > Gurus,
> > > > > >
> > > > > > I have a custom web control that in turn has nested child

> controls. I
> > > > > > want to be able to encapsulated and render any literal HTML and or
> > > > > > server controls placed between the child control's tags. This

> works
> > > > > > fine, unless I add a RequiredFieldValidator control at which point

> my
> > > > > > aspx page fails at

> 'WebControls.BaseValidator.CheckControlValidationP roperty'
> > > > > > with the error message 'Unable to find control id 'TextBox1'
> > > > > > referenced by the 'ControlToValidate' property of
> > > > > > 'RequiredFieldValidator1'.
> > > > > >
> > > > > > My control 'Nested' contains a collection of 'NestedChild'

> controls
> > > > > > with a simple 'Caption' property. I override the 'Render' method

> on
> > > > > > the 'Nested' control and iterate though each NestedChild' in the
> > > > > > collection, outputting the child's literal content to a formatted
> > > > > > table.
> > > > > >
> > > > > > The full code for my control is (please cut-n-paste to replicate

> my
> > > > > > problem):
> > > > > >
> > > > > > using System;
> > > > > > using System.Web.UI;
> > > > > > using System.Web.UI.WebControls;
> > > > > > using System.ComponentModel;
> > > > > > using System.Collections;
> > > > > > using System.Collections.Specialized;
> > > > > > using System.Web.UI.HtmlControls;
> > > > > >
> > > > > > namespace Custom.Web.UI {
> > > > > >
> > > > > > [ToolboxData("<{0}:Nested runat=server></{0}:Nested2>")]
> > > > > > [ParseChildren(true, "NestedChild"), PersistChildren(false)]
> > > > > > public class Nested : WebControl, INamingContainer,
> > > > > > IPostBackDataHandler {
> > > > > >
> > > > > > private NestedChildCollection _NestedChildren = new
> > > > > > NestedChildCollection();
> > > > > >
> > > > > > #region Properties
> > > > > > [
> > > > > >
> > > > >
> > >

> DesignerSerializationVisibility(DesignerSerializat ionVisibility.Content),
> > > > > > PersistenceMode(PersistenceMode.InnerDefaultProper ty),
> > > > > > Description("A collection of nested children"),
> > > > > > ]
> > > > > > public NestedChildCollection NestedChild {
> > > > > > get{ return _NestedChildren; }
> > > > > > }
> > > > > > #endregion
> > > > > >
> > > > > > #region Overrides
> > > > > >
> > > > > > protected override void CreateChildControls() {
> > > > > > this.Controls.Clear();
> > > > > > foreach (NestedChild child in _NestedChildren) {
> > > > > > this.Controls.Add(child);
> > > > > > }
> > > > > > }
> > > > > >
> > > > > > protected override void Render(HtmlTextWriter output) {
> > > > > > output.Write("<b>before</b><br /><hr><br />");
> > > > > > //base.Render(output);
> > > > > > foreach(NestedChild child in _NestedChildren) {
> > > > > > output.Write("* " + child.Caption + "<BR>");
> > > > > >
> > > > > > // Display the literal contents of NestedChild
> > > > > > // in a single table cell
> > > > > > HtmlTableCell td = new HtmlTableCell();
> > > > > > td.Controls.Add(child);
> > > > > >
> > > > > > // Add the table cell to a new table row
> > > > > > HtmlTableRow tr = new HtmlTableRow();
> > > > > > tr.Controls.Add(td);
> > > > > >
> > > > > > // Add the table row to a new table
> > > > > > HtmlTable table = new HtmlTable();
> > > > > > table.ID = this.UniqueID;
> > > > > > table.CellSpacing = 2;
> > > > > > table.CellPadding = 2;
> > > > > > table.Border = 1;
> > > > > > table.Style.Add("background-color", "#C0C0C0");
> > > > > > table.Controls.Add(tr);
> > > > > >
> > > > > > /* FAILS NEXT LINE
> > > > > > Error: "Unable to find control id 'txtTest1' referenced
> > > > > > by the 'ControlToValidate' property of 'valTest1'"
> > > > > > /*
> > > > > > table.RenderControl(output);
> > > > > > }
> > > > > > output.Write("<br /><hr><br /><b>after</b>");
> > > > > > }
> > > > > > #endregion
> > > > > >
> > > > > > #region Implements IPostBackDataHandler (postback only)
> > > > > > bool IPostBackDataHandler.LoadPostData(string strPostDataKey,
> > > > > > NameValueCollection postDataCollection) {
> > > > > > return true;
> > > > > > }
> > > > > > void IPostBackDataHandler.RaisePostDataChangedEvent() {}
> > > > > > #endregion
> > > > > > }
> > > > > >
> > > > > > [ToolboxItem(false), DefaultProperty("Caption")]
> > > > > > public class NestedChild : Control{
> > > > > > private String m_strCaption;
> > > > > > public String Caption {
> > > > > > get { return m_strCaption; }
> > > > > > set { m_strCaption = value; }
> > > > > > }
> > > > > > }
> > > > > >
> > > > > > public class NestedChildCollection : CollectionBase {
> > > > > >
> > > > > > public NestedChild this[int nIndex]{
> > > > > > get { return (NestedChild) base.List[nIndex]; }
> > > > > > }
> > > > > > public void Add(NestedChild child){
> > > > > > base.List.Add(child);
> > > > > > }
> > > > > >
> > > > > > public int IndexOf(NestedChild child){
> > > > > > return base.List.IndexOf(child);
> > > > > > }
> > > > > > }
> > > > > > }
> > > > > >
> > > > > > When deployed the aspx page looks like:
> > > > > >
> > > > > > <form id="Form1" method="post" runat="server">
> > > > > > <P>Nested Control</P>
> > > > > > <P>
> > > > > > <cc1:Nested id="Nested1" runat="server">
> > > > > > <cc1:NestedChild Caption="NestedChild">
> > > > > > <asp:Button id="cmdTest" runat="server" Text="Generate
> > > > > > Event"></asp:Button>
> > > > > > <asp:TextBox id="txtTest" runat="server"></asp:TextBox>
> > > > > > <asp:RequiredFieldValidator id="valTest" runat="server"
> > > > > > ControlToValidate="txtTest"
> > > > > > ErrorMessage="This field is
> > > > > > Required.">*</asp:RequiredFieldValidator>
> > > > > > </cc1:NestedChild>
> > > > > > </cc1:Nested2></P>
> > > > > > <P>&nbsp;</P>
> > > > > > <P>
> > > > > > <asp:label id="lblResult"

> runat="server">lblResult</asp:label></P>
> > > > > > </form>
> > > > > >
> > > > > > If I remove 'RequiredFieldValidator' my control render as

> expected.
> > > > > >
> > > > > > I have noticed, that If I replace the entire formatting logic in

> the
> > > > > > 'Render' method with a call to 'base.Render(output);', the
> > > > > > RequiredFieldValidator works as expected.
> > > > > >
> > > > > > I think this is quite a technical problem and I assume that
> > > > > > 'table.RenderControl(output)' is not preforming the necessary
> > > > > > server-side pre-validation to pass a 'RequiredFieldValidator'. How

> can
> > > > > > I do this?
> > > > > >
> > > > > > Regards,
> > > > > >
> > > > > > Stephen

 
Reply With Quote
 
Alessandro Zifiglio
Guest
Posts: n/a
 
      01-15-2004
have your control implement INamingContainer. This will generate Unique Ids
"Stephen Miller" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) m...
> Peter,
>
> Again, thanks for your on going help.
>
> I have been struggling with this problem for 3+ months and on someone
> else's advice purchased "Developing Microsoft ASP.NET Server Controls
> and Components". Following the book religiously, I started again from
> the "Hello World" example and worked forward to recreate my problem.
> Kothari & Datye's touches on controls "whose nested content does not
> correspond to properties" on pages 332-7, but the example provided is
> very trivial and doesn't address any of the issues I've encountered.
> If I've missed something, please point me to the section.
>
> My control uses the ParseChildrenAttribute attribute with the
> declaration '[ParseChildren(true, "NestedChild")', which defines a
> public property named 'NestedChild', with nested (child) elements
> corresponding to child elements of the 'NestedChild' property. The
> idea with the '_NestedChildren' property is to add each nested child
> element to a collection, which I can iterate through and hide or show
> based on additional conditions. I have extra logic here, which I have
> omitted for clarity.
>
> As you suggested, I have move my code to CreateChildControls. The
> control renders ok in design time, but fails in runtime at
> FillNamedControlsTable with the error message "Multiple controls with
> the same ID 'myControl1' were found. FindControl requires that
> controls have unique IDs". With the RequiredFieldValidator removed,
> the control renders but generates the same error with the buttons
> onClick event. Looking at the source code I notice that the command
> button has now rendered as:
>
> <input type="submit" name="myControl1:cmdTest1" value="Test"
> id="myControl1_cmdTest1" />
>
> I can't compile my code behind with an event handling
> myControl1_cmdTest1.Click, because the compiler is expecting
> cmdTest1.click.
>
> My code for CreateChildControls now looks like:
>
> protected override void CreateChildControls() {
>
> this.Controls.Clear();
> this.Controls.Add(new LiteralControl("<b>before</b><br /><hr><br
> />"));
>
> foreach (NestedChild child in _NestedChildren) {
> //this.Controls.Add(child);
>
> this.Controls.Add(new LiteralControl("* " + child.Caption +
> "<BR>"));
>
> // Display the contents of child in a single cell table
> HtmlTableCell td = new HtmlTableCell();
> td.Style.Add("width", "250px");
> td.Style.Add("height", "100px");
> td.Controls.Add(child);
>
> // Add the table cell to a new table row
> HtmlTableRow tr = new HtmlTableRow();
> tr.Controls.Add(td);
>
> // Add the table row to a new table
> HtmlTable table = new HtmlTable();
> table.ID = this.UniqueID;
> table.Width = this.Width.ToString();
> table.Height = this.Height.ToString();
> table.CellSpacing = 2;
> table.CellPadding = 2;
> table.Border = 1;
> table.Style.Add("background-color", "#C0C0C0");
> table.Controls.Add(tr);
>
> this.Controls.Add(table);
>
> }
> this.Controls.Add(new LiteralControl("<br /><hr><br
> /><b>after</b>"));
> }
>
> Any other suggestions?
>
> Regards,
>
> Stephen
>
>
> "Peter Blum" <(E-Mail Removed)> wrote in message

news:<(E-Mail Removed)>...
> > I strongly encourage you to step back and learn the right way to build
> > custom controls. Otherwise, you will be developing code that may require
> > plenty more debugging and maintenance because it doesn't confirm to how
> > Microsoft designed web controls. I recommend the book "Developing

ASP.NET
> > Server Controls and Components" from Microsoft Press.
> >
> > In your code, I do not understand why you have the _NestedChildren

property.
> > The webcontrol framework automatically supports child controls using the
> > ParseChildrenAttribute. (See the .net docs on this attribute.) I do
> > understand what you are doing in CreateChildControls and that looks OK.
> >
> > Here are my recommendations.
> > - Move the code you have creating the table and its contents into
> > CreateChildControls without removing the existing code.
> > - Any "output.Write()" calls can become LiteralControl objects. (new
> > LiteralControl("<br>"))
> > - Add objects to the Controls collection on your control.
> >
> > Now your validators will be created before OnPreRender occurs. That

allows
> > the webcontrol system that Microsoft designed to call each of your
> > validators own OnPreRender method properly, setting up many things that

are
> > required for validation.
> >
> > --- Peter Blum
> > www.PeterBlum.com
> > Email: (E-Mail Removed)
> > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > news:(E-Mail Removed) m...
> > > Peter,
> > >
> > > I was under the mistaken impression that I was already overriding
> > > CreateChildControls to create the controls with the code:
> > >
> > > protected override void CreateChildControls() {
> > > this.Controls.Clear();
> > > foreach (NestedChild child in _NestedChildren) {
> > > this.Controls.Add(child);
> > > }
> > > }
> > >
> > > If I leave this override out then the control renders fine (with the
> > > RequiredFieldValidators) but fails to generate any server side events.
> > > Moving this code block to OnPreRender (with base.OnPreRend) after
> > > adding the controls doesn't seem to make any difference.
> > >
> > > I have also tried moving the code in the overridden Render method to
> > > the overridden RenderContents method. This doesn't appear to have made
> > > any difference.
> > >
> > > Have I missed the point? Could I beg you for some sample code?
> > >
> > > Thanks,
> > >
> > > Stephen
> > >
> > > "Peter Blum" <(E-Mail Removed)> wrote in message

> > news:<(E-Mail Removed)>...
> > > > I think I see the problem. You are creating your control objects in

the
> > > > Render method. Leave the Render method alone. Generally, only use it

if
> > you
> > > > wanted to output explicit HTML (although there are some cases where

you
> > can
> > > > do what you did.) Instead, create the controls in either the
> > > > CreateChildControls() or OnPreRender method.
> > > >
> > > > Here's the actual problem you are having. Validators must have their
> > > > OnPreRender method run. Because your validators aren't in this

control's
> > > > Controls property, they don't get OnPreRender run. So move your code

to
> > > > OnPreRender and call base.OnPreRender() after those controls are

added
> > to
> > > > the Controls property.
> > > >
> > > > --- Peter Blum
> > > > www.PeterBlum.com
> > > > Email: (E-Mail Removed)
> > > >
> > > > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > > > news:(E-Mail Removed) om...
> > > > > Peter,
> > > > >
> > > > > Thanks for the link. I have enjoyed looking at your site, but its

not
> > > > > going to give me the answer I need. My control needs to be able to
> > > > > render any nested literal content the developer throws at it, so I
> > > > > have to resolve this problem with MS's validators.
> > > > >
> > > > > I have designed my control in such a way that it only needs to
> > > > > validate controls in the same naming container but as you noted,

the
> > > > > error message seems to indicate that the control thinks the

textbox
> > > > > and validator are in different containers.
> > > > >
> > > > > What I find particularly puzzling is that if I simple override the
> > > > > render method with 'base.Render(output)' the validator has not

problem
> > > > > locating the textbox in the container. The problem only seems to

arise
> > > > > when I attempt to encapsulate the controls in my own formatting

with
> > > > > 'table.RenderControl(output)'.
> > > > >
> > > > > Should I be looking at overriding the 'table.RenderControl' method

to
> > > > > make this work? If so what should I be doing?
> > > > >
> > > > > I recently found another commercial product that is able to do

what
> > > > > I'm trying to achive
> > > > > (http://www.infragistics.com/products...sp?sec=0&cat=3)

so I
> > > > > know it must be possible (... and I don't want to pay USD $500)
> > > > >
> > > > > Thanks,
> > > > >
> > > > > Stephen
> > > > >
> > > > >
> > > > >
> > > > > "Peter Blum" <(E-Mail Removed)> wrote in message

> > news:<O#(E-Mail Removed)>...
> > > > > > The ControlToValidate property only accepts the ID of another

> > control in
> > the
> > > > > > same naming container. I believe that this error is due to

naming
> > container
> > > > > > problems. While your code seems to enclose both the textbox and

> > validator
> > > > > > within the same naming container, the error message says

otherwise.
> > > > > >
> > > > > > FYI: If the naming container is indeed the problem, I have a

> > commercial
> > > > > > product that replaces Microsoft's validators to overcome its

many
> > > > > > limitations. My validators support controls in any naming

container.
> > The
> > > > > > product is "Professional Validation And More". Details are at
> > > > > > http://www.peterblum.com/vam/home.aspx.
> > > > > >
> > > > > > --- Peter Blum
> > > > > > www.PeterBlum.com
> > > > > > Email: (E-Mail Removed)
> > > > > >
> > > > > > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > > > > > news:(E-Mail Removed) om...
> > > > > > > Gurus,
> > > > > > >
> > > > > > > I have a custom web control that in turn has nested child

> > controls. I
> > > > > > > want to be able to encapsulated and render any literal HTML

and or
> > > > > > > server controls placed between the child control's tags. This

> > works
> > > > > > > fine, unless I add a RequiredFieldValidator control at which

point
> > my
> > > > > > > aspx page fails at

> > 'WebControls.BaseValidator.CheckControlValidationP roperty'
> > > > > > > with the error message 'Unable to find control id 'TextBox1'
> > > > > > > referenced by the 'ControlToValidate' property of
> > > > > > > 'RequiredFieldValidator1'.
> > > > > > >
> > > > > > > My control 'Nested' contains a collection of 'NestedChild'

> > controls
> > > > > > > with a simple 'Caption' property. I override the 'Render'

method
> > on
> > > > > > > the 'Nested' control and iterate though each NestedChild' in

the
> > > > > > > collection, outputting the child's literal content to a

formatted
> > > > > > > table.
> > > > > > >
> > > > > > > The full code for my control is (please cut-n-paste to

replicate
> > my
> > > > > > > problem):
> > > > > > >
> > > > > > > using System;
> > > > > > > using System.Web.UI;
> > > > > > > using System.Web.UI.WebControls;
> > > > > > > using System.ComponentModel;
> > > > > > > using System.Collections;
> > > > > > > using System.Collections.Specialized;
> > > > > > > using System.Web.UI.HtmlControls;
> > > > > > >
> > > > > > > namespace Custom.Web.UI {
> > > > > > >
> > > > > > > [ToolboxData("<{0}:Nested runat=server></{0}:Nested2>")]
> > > > > > > [ParseChildren(true, "NestedChild"), PersistChildren(false)]
> > > > > > > public class Nested : WebControl, INamingContainer,
> > > > > > > IPostBackDataHandler {
> > > > > > >
> > > > > > > private NestedChildCollection _NestedChildren = new
> > > > > > > NestedChildCollection();
> > > > > > >
> > > > > > > #region Properties
> > > > > > > [
> > > > > > >
> > > > > >
> > > >

> >

DesignerSerializationVisibility(DesignerSerializat ionVisibility.Content),
> > > > > > > PersistenceMode(PersistenceMode.InnerDefaultProper ty),
> > > > > > > Description("A collection of nested children"),
> > > > > > > ]
> > > > > > > public NestedChildCollection NestedChild {
> > > > > > > get{ return _NestedChildren; }
> > > > > > > }
> > > > > > > #endregion
> > > > > > >
> > > > > > > #region Overrides
> > > > > > >
> > > > > > > protected override void CreateChildControls() {
> > > > > > > this.Controls.Clear();
> > > > > > > foreach (NestedChild child in _NestedChildren) {
> > > > > > > this.Controls.Add(child);
> > > > > > > }
> > > > > > > }
> > > > > > >
> > > > > > > protected override void Render(HtmlTextWriter output) {
> > > > > > > output.Write("<b>before</b><br /><hr><br />");
> > > > > > > //base.Render(output);
> > > > > > > foreach(NestedChild child in _NestedChildren) {
> > > > > > > output.Write("* " + child.Caption + "<BR>");
> > > > > > >
> > > > > > > // Display the literal contents of NestedChild
> > > > > > > // in a single table cell
> > > > > > > HtmlTableCell td = new HtmlTableCell();
> > > > > > > td.Controls.Add(child);
> > > > > > >
> > > > > > > // Add the table cell to a new table row
> > > > > > > HtmlTableRow tr = new HtmlTableRow();
> > > > > > > tr.Controls.Add(td);
> > > > > > >
> > > > > > > // Add the table row to a new table
> > > > > > > HtmlTable table = new HtmlTable();
> > > > > > > table.ID = this.UniqueID;
> > > > > > > table.CellSpacing = 2;
> > > > > > > table.CellPadding = 2;
> > > > > > > table.Border = 1;
> > > > > > > table.Style.Add("background-color", "#C0C0C0");
> > > > > > > table.Controls.Add(tr);
> > > > > > >
> > > > > > > /* FAILS NEXT LINE
> > > > > > > Error: "Unable to find control id 'txtTest1'

referenced
> > > > > > > by the 'ControlToValidate' property of 'valTest1'"
> > > > > > > /*
> > > > > > > table.RenderControl(output);
> > > > > > > }
> > > > > > > output.Write("<br /><hr><br /><b>after</b>");
> > > > > > > }
> > > > > > > #endregion
> > > > > > >
> > > > > > > #region Implements IPostBackDataHandler (postback only)
> > > > > > > bool IPostBackDataHandler.LoadPostData(string

strPostDataKey,
> > > > > > > NameValueCollection postDataCollection) {
> > > > > > > return true;
> > > > > > > }
> > > > > > > void IPostBackDataHandler.RaisePostDataChangedEvent() {}
> > > > > > > #endregion
> > > > > > > }
> > > > > > >
> > > > > > > [ToolboxItem(false), DefaultProperty("Caption")]
> > > > > > > public class NestedChild : Control{
> > > > > > > private String m_strCaption;
> > > > > > > public String Caption {
> > > > > > > get { return m_strCaption; }
> > > > > > > set { m_strCaption = value; }
> > > > > > > }
> > > > > > > }
> > > > > > >
> > > > > > > public class NestedChildCollection : CollectionBase {
> > > > > > >
> > > > > > > public NestedChild this[int nIndex]{
> > > > > > > get { return (NestedChild) base.List[nIndex]; }
> > > > > > > }
> > > > > > > public void Add(NestedChild child){
> > > > > > > base.List.Add(child);
> > > > > > > }
> > > > > > >
> > > > > > > public int IndexOf(NestedChild child){
> > > > > > > return base.List.IndexOf(child);
> > > > > > > }
> > > > > > > }
> > > > > > > }
> > > > > > >
> > > > > > > When deployed the aspx page looks like:
> > > > > > >
> > > > > > > <form id="Form1" method="post" runat="server">
> > > > > > > <P>Nested Control</P>
> > > > > > > <P>
> > > > > > > <cc1:Nested id="Nested1" runat="server">
> > > > > > > <cc1:NestedChild Caption="NestedChild">
> > > > > > > <asp:Button id="cmdTest" runat="server" Text="Generate
> > > > > > > Event"></asp:Button>
> > > > > > > <asp:TextBox id="txtTest" runat="server"></asp:TextBox>
> > > > > > > <asp:RequiredFieldValidator id="valTest" runat="server"
> > > > > > > ControlToValidate="txtTest"
> > > > > > > ErrorMessage="This field is
> > > > > > > Required.">*</asp:RequiredFieldValidator>
> > > > > > > </cc1:NestedChild>
> > > > > > > </cc1:Nested2></P>
> > > > > > > <P>&nbsp;</P>
> > > > > > > <P>
> > > > > > > <asp:label id="lblResult"

> > runat="server">lblResult</asp:label></P>
> > > > > > > </form>
> > > > > > >
> > > > > > > If I remove 'RequiredFieldValidator' my control render as

> > expected.
> > > > > > >
> > > > > > > I have noticed, that If I replace the entire formatting logic

in
> > the
> > > > > > > 'Render' method with a call to 'base.Render(output);', the
> > > > > > > RequiredFieldValidator works as expected.
> > > > > > >
> > > > > > > I think this is quite a technical problem and I assume that
> > > > > > > 'table.RenderControl(output)' is not preforming the necessary
> > > > > > > server-side pre-validation to pass a 'RequiredFieldValidator'.

How
> > can
> > > > > > > I do this?
> > > > > > >
> > > > > > > Regards,
> > > > > > >
> > > > > > > Stephen



 
Reply With Quote
 
Alessandro Zifiglio
Guest
Posts: n/a
 
      01-15-2004
in case it is not clear, i'm referring to the template you are using, which
inherits control. When you develop templated controls, you should implement
this interface InameingContainer to avoid naming conflicts on a page. . Your
main class nested is un-necessarily implementing this interface as you
already have clientID which is is unique, and you can name your table :
clientID + "_table";

"Alessandro Zifiglio" <(E-Mail Removed)> wrote in
message news%rNb.3283$(E-Mail Removed)...
> have your control implement INamingContainer. This will generate Unique

Ids
> "Stephen Miller" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed) m...
> > Peter,
> >
> > Again, thanks for your on going help.
> >
> > I have been struggling with this problem for 3+ months and on someone
> > else's advice purchased "Developing Microsoft ASP.NET Server Controls
> > and Components". Following the book religiously, I started again from
> > the "Hello World" example and worked forward to recreate my problem.
> > Kothari & Datye's touches on controls "whose nested content does not
> > correspond to properties" on pages 332-7, but the example provided is
> > very trivial and doesn't address any of the issues I've encountered.
> > If I've missed something, please point me to the section.
> >
> > My control uses the ParseChildrenAttribute attribute with the
> > declaration '[ParseChildren(true, "NestedChild")', which defines a
> > public property named 'NestedChild', with nested (child) elements
> > corresponding to child elements of the 'NestedChild' property. The
> > idea with the '_NestedChildren' property is to add each nested child
> > element to a collection, which I can iterate through and hide or show
> > based on additional conditions. I have extra logic here, which I have
> > omitted for clarity.
> >
> > As you suggested, I have move my code to CreateChildControls. The
> > control renders ok in design time, but fails in runtime at
> > FillNamedControlsTable with the error message "Multiple controls with
> > the same ID 'myControl1' were found. FindControl requires that
> > controls have unique IDs". With the RequiredFieldValidator removed,
> > the control renders but generates the same error with the buttons
> > onClick event. Looking at the source code I notice that the command
> > button has now rendered as:
> >
> > <input type="submit" name="myControl1:cmdTest1" value="Test"
> > id="myControl1_cmdTest1" />
> >
> > I can't compile my code behind with an event handling
> > myControl1_cmdTest1.Click, because the compiler is expecting
> > cmdTest1.click.
> >
> > My code for CreateChildControls now looks like:
> >
> > protected override void CreateChildControls() {
> >
> > this.Controls.Clear();
> > this.Controls.Add(new LiteralControl("<b>before</b><br /><hr><br
> > />"));
> >
> > foreach (NestedChild child in _NestedChildren) {
> > //this.Controls.Add(child);
> >
> > this.Controls.Add(new LiteralControl("* " + child.Caption +
> > "<BR>"));
> >
> > // Display the contents of child in a single cell table
> > HtmlTableCell td = new HtmlTableCell();
> > td.Style.Add("width", "250px");
> > td.Style.Add("height", "100px");
> > td.Controls.Add(child);
> >
> > // Add the table cell to a new table row
> > HtmlTableRow tr = new HtmlTableRow();
> > tr.Controls.Add(td);
> >
> > // Add the table row to a new table
> > HtmlTable table = new HtmlTable();
> > table.ID = this.UniqueID;
> > table.Width = this.Width.ToString();
> > table.Height = this.Height.ToString();
> > table.CellSpacing = 2;
> > table.CellPadding = 2;
> > table.Border = 1;
> > table.Style.Add("background-color", "#C0C0C0");
> > table.Controls.Add(tr);
> >
> > this.Controls.Add(table);
> >
> > }
> > this.Controls.Add(new LiteralControl("<br /><hr><br
> > /><b>after</b>"));
> > }
> >
> > Any other suggestions?
> >
> > Regards,
> >
> > Stephen
> >
> >
> > "Peter Blum" <(E-Mail Removed)> wrote in message

> news:<(E-Mail Removed)>...
> > > I strongly encourage you to step back and learn the right way to build
> > > custom controls. Otherwise, you will be developing code that may

require
> > > plenty more debugging and maintenance because it doesn't confirm to

how
> > > Microsoft designed web controls. I recommend the book "Developing

> ASP.NET
> > > Server Controls and Components" from Microsoft Press.
> > >
> > > In your code, I do not understand why you have the _NestedChildren

> property.
> > > The webcontrol framework automatically supports child controls using

the
> > > ParseChildrenAttribute. (See the .net docs on this attribute.) I do
> > > understand what you are doing in CreateChildControls and that looks

OK.
> > >
> > > Here are my recommendations.
> > > - Move the code you have creating the table and its contents into
> > > CreateChildControls without removing the existing code.
> > > - Any "output.Write()" calls can become LiteralControl objects. (new
> > > LiteralControl("<br>"))
> > > - Add objects to the Controls collection on your control.
> > >
> > > Now your validators will be created before OnPreRender occurs. That

> allows
> > > the webcontrol system that Microsoft designed to call each of your
> > > validators own OnPreRender method properly, setting up many things

that
> are
> > > required for validation.
> > >
> > > --- Peter Blum
> > > www.PeterBlum.com
> > > Email: (E-Mail Removed)
> > > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > > news:(E-Mail Removed) m...
> > > > Peter,
> > > >
> > > > I was under the mistaken impression that I was already overriding
> > > > CreateChildControls to create the controls with the code:
> > > >
> > > > protected override void CreateChildControls() {
> > > > this.Controls.Clear();
> > > > foreach (NestedChild child in _NestedChildren) {
> > > > this.Controls.Add(child);
> > > > }
> > > > }
> > > >
> > > > If I leave this override out then the control renders fine (with the
> > > > RequiredFieldValidators) but fails to generate any server side

events.
> > > > Moving this code block to OnPreRender (with base.OnPreRend) after
> > > > adding the controls doesn't seem to make any difference.
> > > >
> > > > I have also tried moving the code in the overridden Render method to
> > > > the overridden RenderContents method. This doesn't appear to have

made
> > > > any difference.
> > > >
> > > > Have I missed the point? Could I beg you for some sample code?
> > > >
> > > > Thanks,
> > > >
> > > > Stephen
> > > >
> > > > "Peter Blum" <(E-Mail Removed)> wrote in message
> > > news:<(E-Mail Removed)>...
> > > > > I think I see the problem. You are creating your control objects

in
> the
> > > > > Render method. Leave the Render method alone. Generally, only use

it
> if
> > > you
> > > > > wanted to output explicit HTML (although there are some cases

where
> you
> > > can
> > > > > do what you did.) Instead, create the controls in either the
> > > > > CreateChildControls() or OnPreRender method.
> > > > >
> > > > > Here's the actual problem you are having. Validators must have

their
> > > > > OnPreRender method run. Because your validators aren't in this

> control's
> > > > > Controls property, they don't get OnPreRender run. So move your

code
> to
> > > > > OnPreRender and call base.OnPreRender() after those controls are

> added
> > > to
> > > > > the Controls property.
> > > > >
> > > > > --- Peter Blum
> > > > > www.PeterBlum.com
> > > > > Email: (E-Mail Removed)
> > > > >
> > > > > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > > > > news:(E-Mail Removed) om...
> > > > > > Peter,
> > > > > >
> > > > > > Thanks for the link. I have enjoyed looking at your site, but

its
> not
> > > > > > going to give me the answer I need. My control needs to be able

to
> > > > > > render any nested literal content the developer throws at it, so

I
> > > > > > have to resolve this problem with MS's validators.
> > > > > >
> > > > > > I have designed my control in such a way that it only needs to
> > > > > > validate controls in the same naming container but as you noted,

> the
> > > > > > error message seems to indicate that the control thinks the

> textbox
> > > > > > and validator are in different containers.
> > > > > >
> > > > > > What I find particularly puzzling is that if I simple override

the
> > > > > > render method with 'base.Render(output)' the validator has not

> problem
> > > > > > locating the textbox in the container. The problem only seems to

> arise
> > > > > > when I attempt to encapsulate the controls in my own formatting

> with
> > > > > > 'table.RenderControl(output)'.
> > > > > >
> > > > > > Should I be looking at overriding the 'table.RenderControl'

method
> to
> > > > > > make this work? If so what should I be doing?
> > > > > >
> > > > > > I recently found another commercial product that is able to do

> what
> > > > > > I'm trying to achive
> > > > > >

(http://www.infragistics.com/products...sp?sec=0&cat=3)
> so I
> > > > > > know it must be possible (... and I don't want to pay USD $500)
> > > > > >
> > > > > > Thanks,
> > > > > >
> > > > > > Stephen
> > > > > >
> > > > > >
> > > > > >
> > > > > > "Peter Blum" <(E-Mail Removed)> wrote in message
> > > news:<O#(E-Mail Removed)>...
> > > > > > > The ControlToValidate property only accepts the ID of another
> > > control in
> > > the
> > > > > > > same naming container. I believe that this error is due to

> naming
> > > container
> > > > > > > problems. While your code seems to enclose both the textbox

and
> > > validator
> > > > > > > within the same naming container, the error message says

> otherwise.
> > > > > > >
> > > > > > > FYI: If the naming container is indeed the problem, I have a
> > > commercial
> > > > > > > product that replaces Microsoft's validators to overcome its

> many
> > > > > > > limitations. My validators support controls in any naming

> container.
> > > The
> > > > > > > product is "Professional Validation And More". Details are at
> > > > > > > http://www.peterblum.com/vam/home.aspx.
> > > > > > >
> > > > > > > --- Peter Blum
> > > > > > > www.PeterBlum.com
> > > > > > > Email: (E-Mail Removed)
> > > > > > >
> > > > > > > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > > > > > > news:(E-Mail Removed) om...
> > > > > > > > Gurus,
> > > > > > > >
> > > > > > > > I have a custom web control that in turn has nested child
> > > controls. I
> > > > > > > > want to be able to encapsulated and render any literal HTML

> and or
> > > > > > > > server controls placed between the child control's tags.

This
> > > works
> > > > > > > > fine, unless I add a RequiredFieldValidator control at which

> point
> > > my
> > > > > > > > aspx page fails at
> > > 'WebControls.BaseValidator.CheckControlValidationP roperty'
> > > > > > > > with the error message 'Unable to find control id 'TextBox1'
> > > > > > > > referenced by the 'ControlToValidate' property of
> > > > > > > > 'RequiredFieldValidator1'.
> > > > > > > >
> > > > > > > > My control 'Nested' contains a collection of 'NestedChild'
> > > controls
> > > > > > > > with a simple 'Caption' property. I override the 'Render'

> method
> > > on
> > > > > > > > the 'Nested' control and iterate though each NestedChild' in

> the
> > > > > > > > collection, outputting the child's literal content to a

> formatted
> > > > > > > > table.
> > > > > > > >
> > > > > > > > The full code for my control is (please cut-n-paste to

> replicate
> > > my
> > > > > > > > problem):
> > > > > > > >
> > > > > > > > using System;
> > > > > > > > using System.Web.UI;
> > > > > > > > using System.Web.UI.WebControls;
> > > > > > > > using System.ComponentModel;
> > > > > > > > using System.Collections;
> > > > > > > > using System.Collections.Specialized;
> > > > > > > > using System.Web.UI.HtmlControls;
> > > > > > > >
> > > > > > > > namespace Custom.Web.UI {
> > > > > > > >
> > > > > > > > [ToolboxData("<{0}:Nested runat=server></{0}:Nested2>")]
> > > > > > > > [ParseChildren(true, "NestedChild"),

PersistChildren(false)]
> > > > > > > > public class Nested : WebControl, INamingContainer,
> > > > > > > > IPostBackDataHandler {
> > > > > > > >
> > > > > > > > private NestedChildCollection _NestedChildren = new
> > > > > > > > NestedChildCollection();
> > > > > > > >
> > > > > > > > #region Properties
> > > > > > > > [
> > > > > > > >
> > > > > > >
> > > > >
> > >

> DesignerSerializationVisibility(DesignerSerializat ionVisibility.Content),
> > > > > > > > PersistenceMode(PersistenceMode.InnerDefaultProper ty),
> > > > > > > > Description("A collection of nested children"),
> > > > > > > > ]
> > > > > > > > public NestedChildCollection NestedChild {
> > > > > > > > get{ return _NestedChildren; }
> > > > > > > > }
> > > > > > > > #endregion
> > > > > > > >
> > > > > > > > #region Overrides
> > > > > > > >
> > > > > > > > protected override void CreateChildControls() {
> > > > > > > > this.Controls.Clear();
> > > > > > > > foreach (NestedChild child in _NestedChildren) {
> > > > > > > > this.Controls.Add(child);
> > > > > > > > }
> > > > > > > > }
> > > > > > > >
> > > > > > > > protected override void Render(HtmlTextWriter output) {
> > > > > > > > output.Write("<b>before</b><br /><hr><br />");
> > > > > > > > //base.Render(output);
> > > > > > > > foreach(NestedChild child in _NestedChildren) {
> > > > > > > > output.Write("* " + child.Caption + "<BR>");
> > > > > > > >
> > > > > > > > // Display the literal contents of NestedChild
> > > > > > > > // in a single table cell
> > > > > > > > HtmlTableCell td = new HtmlTableCell();
> > > > > > > > td.Controls.Add(child);
> > > > > > > >
> > > > > > > > // Add the table cell to a new table row
> > > > > > > > HtmlTableRow tr = new HtmlTableRow();
> > > > > > > > tr.Controls.Add(td);
> > > > > > > >
> > > > > > > > // Add the table row to a new table
> > > > > > > > HtmlTable table = new HtmlTable();
> > > > > > > > table.ID = this.UniqueID;
> > > > > > > > table.CellSpacing = 2;
> > > > > > > > table.CellPadding = 2;
> > > > > > > > table.Border = 1;
> > > > > > > > table.Style.Add("background-color", "#C0C0C0");
> > > > > > > > table.Controls.Add(tr);
> > > > > > > >
> > > > > > > > /* FAILS NEXT LINE
> > > > > > > > Error: "Unable to find control id 'txtTest1'

> referenced
> > > > > > > > by the 'ControlToValidate' property of 'valTest1'"
> > > > > > > > /*
> > > > > > > > table.RenderControl(output);
> > > > > > > > }
> > > > > > > > output.Write("<br /><hr><br /><b>after</b>");
> > > > > > > > }
> > > > > > > > #endregion
> > > > > > > >
> > > > > > > > #region Implements IPostBackDataHandler (postback only)
> > > > > > > > bool IPostBackDataHandler.LoadPostData(string

> strPostDataKey,
> > > > > > > > NameValueCollection postDataCollection) {
> > > > > > > > return true;
> > > > > > > > }
> > > > > > > > void IPostBackDataHandler.RaisePostDataChangedEvent() {}
> > > > > > > > #endregion
> > > > > > > > }
> > > > > > > >
> > > > > > > > [ToolboxItem(false), DefaultProperty("Caption")]
> > > > > > > > public class NestedChild : Control{
> > > > > > > > private String m_strCaption;
> > > > > > > > public String Caption {
> > > > > > > > get { return m_strCaption; }
> > > > > > > > set { m_strCaption = value; }
> > > > > > > > }
> > > > > > > > }
> > > > > > > >
> > > > > > > > public class NestedChildCollection : CollectionBase {
> > > > > > > >
> > > > > > > > public NestedChild this[int nIndex]{
> > > > > > > > get { return (NestedChild) base.List[nIndex]; }
> > > > > > > > }
> > > > > > > > public void Add(NestedChild child){
> > > > > > > > base.List.Add(child);
> > > > > > > > }
> > > > > > > >
> > > > > > > > public int IndexOf(NestedChild child){
> > > > > > > > return base.List.IndexOf(child);
> > > > > > > > }
> > > > > > > > }
> > > > > > > > }
> > > > > > > >
> > > > > > > > When deployed the aspx page looks like:
> > > > > > > >
> > > > > > > > <form id="Form1" method="post" runat="server">
> > > > > > > > <P>Nested Control</P>
> > > > > > > > <P>
> > > > > > > > <cc1:Nested id="Nested1" runat="server">
> > > > > > > > <cc1:NestedChild Caption="NestedChild">
> > > > > > > > <asp:Button id="cmdTest" runat="server" Text="Generate
> > > > > > > > Event"></asp:Button>
> > > > > > > > <asp:TextBox id="txtTest" runat="server"></asp:TextBox>
> > > > > > > > <asp:RequiredFieldValidator id="valTest" runat="server"
> > > > > > > > ControlToValidate="txtTest"
> > > > > > > > ErrorMessage="This field is
> > > > > > > > Required.">*</asp:RequiredFieldValidator>
> > > > > > > > </cc1:NestedChild>
> > > > > > > > </cc1:Nested2></P>
> > > > > > > > <P>&nbsp;</P>
> > > > > > > > <P>
> > > > > > > > <asp:label id="lblResult"
> > > runat="server">lblResult</asp:label></P>
> > > > > > > > </form>
> > > > > > > >
> > > > > > > > If I remove 'RequiredFieldValidator' my control render as
> > > expected.
> > > > > > > >
> > > > > > > > I have noticed, that If I replace the entire formatting

logic
> in
> > > the
> > > > > > > > 'Render' method with a call to 'base.Render(output);', the
> > > > > > > > RequiredFieldValidator works as expected.
> > > > > > > >
> > > > > > > > I think this is quite a technical problem and I assume that
> > > > > > > > 'table.RenderControl(output)' is not preforming the

necessary
> > > > > > > > server-side pre-validation to pass a

'RequiredFieldValidator'.
> How
> > > can
> > > > > > > > I do this?
> > > > > > > >
> > > > > > > > Regards,
> > > > > > > >
> > > > > > > > Stephen

>
>



 
Reply With Quote
 
Stephen Miller
Guest
Posts: n/a
 
      01-17-2004
Alessandro,

That's the missing piece of the puzzle!

I can see that I am now uncessarily implementing InamingContainer
twice, however I found that if I gave the table a unique name (ie.
table.ID = "_" + this.ID; ) and removed InamingContainer from the main
class ('Nested'), then the control correctly renders any nested server
controls placed within the 'NestedChild' tags (including
RequiredFieldValidator's), but the command button was unable to
generate a server-side onClick event.

Having two implementations of InamingContainer does produce
complicated naming of child controls, when rendered (ie cmdTest
becomes Nested1:_ctl2:cmdTest). Is there a better way? Should I now be
moving my implementation of IPostBackDataHandler to the 'NestedChild'
class'?

Regards,

Stephen


"Alessandro Zifiglio" <(E-Mail Removed)> wrote in message news:<PdtNb.3378$(E-Mail Removed)>...
> in case it is not clear, i'm referring to the template you are using, which
> inherits control. When you develop templated controls, you should implement
> this interface InameingContainer to avoid naming conflicts on a page. . Your
> main class nested is un-necessarily implementing this interface as you
> already have clientID which is is unique, and you can name your table :
> clientID + "_table";
>
> "Alessandro Zifiglio" <(E-Mail Removed)> wrote in
> message news%rNb.3283$(E-Mail Removed)...
> > have your control implement INamingContainer. This will generate Unique

> Ids
> > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > news:(E-Mail Removed) m...
> > > Peter,
> > >
> > > Again, thanks for your on going help.
> > >
> > > I have been struggling with this problem for 3+ months and on someone
> > > else's advice purchased "Developing Microsoft ASP.NET Server Controls
> > > and Components". Following the book religiously, I started again from
> > > the "Hello World" example and worked forward to recreate my problem.
> > > Kothari & Datye's touches on controls "whose nested content does not
> > > correspond to properties" on pages 332-7, but the example provided is
> > > very trivial and doesn't address any of the issues I've encountered.
> > > If I've missed something, please point me to the section.
> > >
> > > My control uses the ParseChildrenAttribute attribute with the
> > > declaration '[ParseChildren(true, "NestedChild")', which defines a
> > > public property named 'NestedChild', with nested (child) elements
> > > corresponding to child elements of the 'NestedChild' property. The
> > > idea with the '_NestedChildren' property is to add each nested child
> > > element to a collection, which I can iterate through and hide or show
> > > based on additional conditions. I have extra logic here, which I have
> > > omitted for clarity.
> > >
> > > As you suggested, I have move my code to CreateChildControls. The
> > > control renders ok in design time, but fails in runtime at
> > > FillNamedControlsTable with the error message "Multiple controls with
> > > the same ID 'myControl1' were found. FindControl requires that
> > > controls have unique IDs". With the RequiredFieldValidator removed,
> > > the control renders but generates the same error with the buttons
> > > onClick event. Looking at the source code I notice that the command
> > > button has now rendered as:
> > >
> > > <input type="submit" name="myControl1:cmdTest1" value="Test"
> > > id="myControl1_cmdTest1" />
> > >
> > > I can't compile my code behind with an event handling
> > > myControl1_cmdTest1.Click, because the compiler is expecting
> > > cmdTest1.click.
> > >
> > > My code for CreateChildControls now looks like:
> > >
> > > protected override void CreateChildControls() {
> > >
> > > this.Controls.Clear();
> > > this.Controls.Add(new LiteralControl("<b>before</b><br /><hr><br
> > > />"));
> > >
> > > foreach (NestedChild child in _NestedChildren) {
> > > //this.Controls.Add(child);
> > >
> > > this.Controls.Add(new LiteralControl("* " + child.Caption +
> > > "<BR>"));
> > >
> > > // Display the contents of child in a single cell table
> > > HtmlTableCell td = new HtmlTableCell();
> > > td.Style.Add("width", "250px");
> > > td.Style.Add("height", "100px");
> > > td.Controls.Add(child);
> > >
> > > // Add the table cell to a new table row
> > > HtmlTableRow tr = new HtmlTableRow();
> > > tr.Controls.Add(td);
> > >
> > > // Add the table row to a new table
> > > HtmlTable table = new HtmlTable();
> > > table.ID = this.UniqueID;
> > > table.Width = this.Width.ToString();
> > > table.Height = this.Height.ToString();
> > > table.CellSpacing = 2;
> > > table.CellPadding = 2;
> > > table.Border = 1;
> > > table.Style.Add("background-color", "#C0C0C0");
> > > table.Controls.Add(tr);
> > >
> > > this.Controls.Add(table);
> > >
> > > }
> > > this.Controls.Add(new LiteralControl("<br /><hr><br
> > > /><b>after</b>"));
> > > }
> > >
> > > Any other suggestions?
> > >
> > > Regards,
> > >
> > > Stephen
> > >
> > >
> > > "Peter Blum" <(E-Mail Removed)> wrote in message

> news:<(E-Mail Removed)>...
> > > > I strongly encourage you to step back and learn the right way to build
> > > > custom controls. Otherwise, you will be developing code that may

> require
> > > > plenty more debugging and maintenance because it doesn't confirm to

> how
> > > > Microsoft designed web controls. I recommend the book "Developing

> ASP.NET
> > > > Server Controls and Components" from Microsoft Press.
> > > >
> > > > In your code, I do not understand why you have the _NestedChildren

> property.
> > > > The webcontrol framework automatically supports child controls using

> the
> > > > ParseChildrenAttribute. (See the .net docs on this attribute.) I do
> > > > understand what you are doing in CreateChildControls and that looks

> OK.
> > > >
> > > > Here are my recommendations.
> > > > - Move the code you have creating the table and its contents into
> > > > CreateChildControls without removing the existing code.
> > > > - Any "output.Write()" calls can become LiteralControl objects. (new
> > > > LiteralControl("<br>"))
> > > > - Add objects to the Controls collection on your control.
> > > >
> > > > Now your validators will be created before OnPreRender occurs. That

> allows
> > > > the webcontrol system that Microsoft designed to call each of your
> > > > validators own OnPreRender method properly, setting up many things

> that
> are
> > > > required for validation.
> > > >
> > > > --- Peter Blum
> > > > www.PeterBlum.com
> > > > Email: (E-Mail Removed)
> > > > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > > > news:(E-Mail Removed) m...
> > > > > Peter,
> > > > >
> > > > > I was under the mistaken impression that I was already overriding
> > > > > CreateChildControls to create the controls with the code:
> > > > >
> > > > > protected override void CreateChildControls() {
> > > > > this.Controls.Clear();
> > > > > foreach (NestedChild child in _NestedChildren) {
> > > > > this.Controls.Add(child);
> > > > > }
> > > > > }
> > > > >
> > > > > If I leave this override out then the control renders fine (with the
> > > > > RequiredFieldValidators) but fails to generate any server side

> events.
> > > > > Moving this code block to OnPreRender (with base.OnPreRend) after
> > > > > adding the controls doesn't seem to make any difference.
> > > > >
> > > > > I have also tried moving the code in the overridden Render method to
> > > > > the overridden RenderContents method. This doesn't appear to have

> made
> > > > > any difference.
> > > > >
> > > > > Have I missed the point? Could I beg you for some sample code?
> > > > >
> > > > > Thanks,
> > > > >
> > > > > Stephen
> > > > >
> > > > > "Peter Blum" <(E-Mail Removed)> wrote in message

> news:<(E-Mail Removed)>...
> > > > > > I think I see the problem. You are creating your control objects

> in
> the
> > > > > > Render method. Leave the Render method alone. Generally, only use

> it
> if
> you
> > > > > > wanted to output explicit HTML (although there are some cases

> where
> you
> can
> > > > > > do what you did.) Instead, create the controls in either the
> > > > > > CreateChildControls() or OnPreRender method.
> > > > > >
> > > > > > Here's the actual problem you are having. Validators must have

> their
> > > > > > OnPreRender method run. Because your validators aren't in this

> control's
> > > > > > Controls property, they don't get OnPreRender run. So move your

> code
> to
> > > > > > OnPreRender and call base.OnPreRender() after those controls are

> added
> to
> > > > > > the Controls property.
> > > > > >
> > > > > > --- Peter Blum
> > > > > > www.PeterBlum.com
> > > > > > Email: (E-Mail Removed)
> > > > > >
> > > > > > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > > > > > news:(E-Mail Removed) om...
> > > > > > > Peter,
> > > > > > >
> > > > > > > Thanks for the link. I have enjoyed looking at your site, but

> its
> not
> > > > > > > going to give me the answer I need. My control needs to be able

> to
> > > > > > > render any nested literal content the developer throws at it, so

> I
> > > > > > > have to resolve this problem with MS's validators.
> > > > > > >
> > > > > > > I have designed my control in such a way that it only needs to
> > > > > > > validate controls in the same naming container but as you noted,

> the
> > > > > > > error message seems to indicate that the control thinks the

> textbox
> > > > > > > and validator are in different containers.
> > > > > > >
> > > > > > > What I find particularly puzzling is that if I simple override

> the
> > > > > > > render method with 'base.Render(output)' the validator has not

> problem
> > > > > > > locating the textbox in the container. The problem only seems to

> arise
> > > > > > > when I attempt to encapsulate the controls in my own formatting

> with
> > > > > > > 'table.RenderControl(output)'.
> > > > > > >
> > > > > > > Should I be looking at overriding the 'table.RenderControl'

> method
> to
> > > > > > > make this work? If so what should I be doing?
> > > > > > >
> > > > > > > I recently found another commercial product that is able to do

> what
> > > > > > > I'm trying to achive
> > > > > > >

> (http://www.infragistics.com/products...sp?sec=0&cat=3)
> so I
> > > > > > > know it must be possible (... and I don't want to pay USD $500)
> > > > > > >
> > > > > > > Thanks,
> > > > > > >
> > > > > > > Stephen
> > > > > > >
> > > > > > >
> > > > > > >
> > > > > > > "Peter Blum" <(E-Mail Removed)> wrote in message

> news:<O#(E-Mail Removed)>...
> > > > > > > > The ControlToValidate property only accepts the ID of another
> > > > control in
> > > > the
> > > > > > > > same naming container. I believe that this error is due to

> naming
> container
> > > > > > > > problems. While your code seems to enclose both the textbox

> and
> validator
> > > > > > > > within the same naming container, the error message says

> otherwise.
> > > > > > > >
> > > > > > > > FYI: If the naming container is indeed the problem, I have a

> commercial
> > > > > > > > product that replaces Microsoft's validators to overcome its

> many
> > > > > > > > limitations. My validators support controls in any naming

> container.
> The
> > > > > > > > product is "Professional Validation And More". Details are at
> > > > > > > > http://www.peterblum.com/vam/home.aspx.
> > > > > > > >
> > > > > > > > --- Peter Blum
> > > > > > > > www.PeterBlum.com
> > > > > > > > Email: (E-Mail Removed)
> > > > > > > >
> > > > > > > > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > > > > > > > news:(E-Mail Removed) om...
> > > > > > > > > Gurus,
> > > > > > > > >
> > > > > > > > > I have a custom web control that in turn has nested child

> controls. I
> > > > > > > > > want to be able to encapsulated and render any literal HTML

> and or
> > > > > > > > > server controls placed between the child control's tags.

> This
> works
> > > > > > > > > fine, unless I add a RequiredFieldValidator control at which

> point
> my
> > > > > > > > > aspx page fails at

> 'WebControls.BaseValidator.CheckControlValidationP roperty'
> > > > > > > > > with the error message 'Unable to find control id 'TextBox1'
> > > > > > > > > referenced by the 'ControlToValidate' property of
> > > > > > > > > 'RequiredFieldValidator1'.
> > > > > > > > >
> > > > > > > > > My control 'Nested' contains a collection of 'NestedChild'

> controls
> > > > > > > > > with a simple 'Caption' property. I override the 'Render'

> method
> on
> > > > > > > > > the 'Nested' control and iterate though each NestedChild' in

> the
> > > > > > > > > collection, outputting the child's literal content to a

> formatted
> > > > > > > > > table.
> > > > > > > > >
> > > > > > > > > The full code for my control is (please cut-n-paste to

> replicate
> my
> > > > > > > > > problem):
> > > > > > > > >
> > > > > > > > > using System;
> > > > > > > > > using System.Web.UI;
> > > > > > > > > using System.Web.UI.WebControls;
> > > > > > > > > using System.ComponentModel;
> > > > > > > > > using System.Collections;
> > > > > > > > > using System.Collections.Specialized;
> > > > > > > > > using System.Web.UI.HtmlControls;
> > > > > > > > >
> > > > > > > > > namespace Custom.Web.UI {
> > > > > > > > >
> > > > > > > > > [ToolboxData("<{0}:Nested runat=server></{0}:Nested2>")]
> > > > > > > > > [ParseChildren(true, "NestedChild"),

> PersistChildren(false)]
> > > > > > > > > public class Nested : WebControl, INamingContainer,
> > > > > > > > > IPostBackDataHandler {
> > > > > > > > >
> > > > > > > > > private NestedChildCollection _NestedChildren = new
> > > > > > > > > NestedChildCollection();
> > > > > > > > >
> > > > > > > > > #region Properties
> > > > > > > > > [
> > > > > > > > >
> > > > > > > >
> > > > > >
> > > >

> DesignerSerializationVisibility(DesignerSerializat ionVisibility.Content),
> > > > > > > > > PersistenceMode(PersistenceMode.InnerDefaultProper ty),
> > > > > > > > > Description("A collection of nested children"),
> > > > > > > > > ]
> > > > > > > > > public NestedChildCollection NestedChild {
> > > > > > > > > get{ return _NestedChildren; }
> > > > > > > > > }
> > > > > > > > > #endregion
> > > > > > > > >
> > > > > > > > > #region Overrides
> > > > > > > > >
> > > > > > > > > protected override void CreateChildControls() {
> > > > > > > > > this.Controls.Clear();
> > > > > > > > > foreach (NestedChild child in _NestedChildren) {
> > > > > > > > > this.Controls.Add(child);
> > > > > > > > > }
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > protected override void Render(HtmlTextWriter output) {
> > > > > > > > > output.Write("<b>before</b><br /><hr><br />");
> > > > > > > > > //base.Render(output);
> > > > > > > > > foreach(NestedChild child in _NestedChildren) {
> > > > > > > > > output.Write("* " + child.Caption + "<BR>");
> > > > > > > > >
> > > > > > > > > // Display the literal contents of NestedChild
> > > > > > > > > // in a single table cell
> > > > > > > > > HtmlTableCell td = new HtmlTableCell();
> > > > > > > > > td.Controls.Add(child);
> > > > > > > > >
> > > > > > > > > // Add the table cell to a new table row
> > > > > > > > > HtmlTableRow tr = new HtmlTableRow();
> > > > > > > > > tr.Controls.Add(td);
> > > > > > > > >
> > > > > > > > > // Add the table row to a new table
> > > > > > > > > HtmlTable table = new HtmlTable();
> > > > > > > > > table.ID = this.UniqueID;
> > > > > > > > > table.CellSpacing = 2;
> > > > > > > > > table.CellPadding = 2;
> > > > > > > > > table.Border = 1;
> > > > > > > > > table.Style.Add("background-color", "#C0C0C0");
> > > > > > > > > table.Controls.Add(tr);
> > > > > > > > >
> > > > > > > > > /* FAILS NEXT LINE
> > > > > > > > > Error: "Unable to find control id 'txtTest1'

> referenced
> > > > > > > > > by the 'ControlToValidate' property of 'valTest1'"
> > > > > > > > > /*
> > > > > > > > > table.RenderControl(output);
> > > > > > > > > }
> > > > > > > > > output.Write("<br /><hr><br /><b>after</b>");
> > > > > > > > > }
> > > > > > > > > #endregion
> > > > > > > > >
> > > > > > > > > #region Implements IPostBackDataHandler (postback only)
> > > > > > > > > bool IPostBackDataHandler.LoadPostData(string

> strPostDataKey,
> > > > > > > > > NameValueCollection postDataCollection) {
> > > > > > > > > return true;
> > > > > > > > > }
> > > > > > > > > void IPostBackDataHandler.RaisePostDataChangedEvent() {}
> > > > > > > > > #endregion
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > [ToolboxItem(false), DefaultProperty("Caption")]
> > > > > > > > > public class NestedChild : Control{
> > > > > > > > > private String m_strCaption;
> > > > > > > > > public String Caption {
> > > > > > > > > get { return m_strCaption; }
> > > > > > > > > set { m_strCaption = value; }
> > > > > > > > > }
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public class NestedChildCollection : CollectionBase {
> > > > > > > > >
> > > > > > > > > public NestedChild this[int nIndex]{
> > > > > > > > > get { return (NestedChild) base.List[nIndex]; }
> > > > > > > > > }
> > > > > > > > > public void Add(NestedChild child){
> > > > > > > > > base.List.Add(child);
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public int IndexOf(NestedChild child){
> > > > > > > > > return base.List.IndexOf(child);
> > > > > > > > > }
> > > > > > > > > }
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > When deployed the aspx page looks like:
> > > > > > > > >
> > > > > > > > > <form id="Form1" method="post" runat="server">
> > > > > > > > > <P>Nested Control</P>
> > > > > > > > > <P>
> > > > > > > > > <cc1:Nested id="Nested1" runat="server">
> > > > > > > > > <cc1:NestedChild Caption="NestedChild">
> > > > > > > > > <asp:Button id="cmdTest" runat="server" Text="Generate
> > > > > > > > > Event"></asp:Button>
> > > > > > > > > <asp:TextBox id="txtTest" runat="server"></asp:TextBox>
> > > > > > > > > <asp:RequiredFieldValidator id="valTest" runat="server"
> > > > > > > > > ControlToValidate="txtTest"
> > > > > > > > > ErrorMessage="This field is
> > > > > > > > > Required.">*</asp:RequiredFieldValidator>
> > > > > > > > > </cc1:NestedChild>
> > > > > > > > > </cc1:Nested2></P>
> > > > > > > > > <P>&nbsp;</P>
> > > > > > > > > <P>
> > > > > > > > > <asp:label id="lblResult"

> runat="server">lblResult</asp:label></P>
> > > > > > > > > </form>
> > > > > > > > >
> > > > > > > > > If I remove 'RequiredFieldValidator' my control render as

> expected.
> > > > > > > > >
> > > > > > > > > I have noticed, that If I replace the entire formatting

> logic
> in
> the
> > > > > > > > > 'Render' method with a call to 'base.Render(output);', the
> > > > > > > > > RequiredFieldValidator works as expected.
> > > > > > > > >
> > > > > > > > > I think this is quite a technical problem and I assume that
> > > > > > > > > 'table.RenderControl(output)' is not preforming the

> necessary
> > > > > > > > > server-side pre-validation to pass a

> 'RequiredFieldValidator'.
> How
> can
> > > > > > > > > I do this?
> > > > > > > > >
> > > > > > > > > Regards,
> > > > > > > > >
> > > > > > > > > Stephen

> >
> >

 
Reply With Quote
 
Stephen Miller
Guest
Posts: n/a
 
      01-17-2004
Guys,

.... Two steps forward, one step back

I've found another peculiarity regarding event handling. Extending the
simplified version of the code posted previously, my control also
implements IpostBackEventHandler and raises a default event
'SelectedIndexChanged' for the onClick event for each nested child's
table cell. For example:

....
td.Attributes.Add("onclick", "javascript:" +
Page.GetPostBackEventReference(this,
_NestedChildren.IndexOf(NestedChild).ToString()))
....

I have implemented the RaisePostBackEvent to pass the event argument
to a local variable.

void IPostBackEventHandler.RaisePostBackEvent(String strEventArgument)
{

if (strEventArgument == null)
return;

_selectedIndex = Int32.Parse(strEventArgument);

}

This enables a user to select a particular NestedChild, with further
logic on postback.

Using page tracing and liberal use of the 'Page.Trace.Write' method, I
have observed some strange postback handling.

If a selected NestedChild contains just simple HTML markup, then the
processing order on onClick is:

LoadViewState
ProcessPostData
`-> IPostBackDataHandler.LoadPostData
ChangedEvents
`-> IPostBackDataHandler.RaisePostDataChangedEvent
PostBackEvent
`-> IPostBackEventHandler.RaisePostBackEvent
PreRender
`-> CreateChildControls
SaveViewState
Render

If however, I select a NestedChild that contains server controls, then
the processing order becomes:

LoadViewState
ProcessPostData
`-> CreateChildControls
`-> IPostBackDataHandler.LoadPostData
ChangedEvents
`-> IPostBackDataHandler.RaisePostDataChangedEvent
PostBackEvent
`-> IPostBackEventHandler.RaisePostBackEvent
PreRender
SaveViewState
Render

I'm expecting CreateChildControls to be called in the PreRender phase
(after RaisePostBackEvent, when the _selectedIndex becomes known). Why
is CreateChildControls not being called in PreRender, when the
NestedChild that contains server controls? How can I raise the
PostBackEvent (and the OnSelectedIndexChanged method), before the
CreateChildControls method is called?

Regards,

Stephen

"Alessandro Zifiglio" <(E-Mail Removed)> wrote in message news:<PdtNb.3378$(E-Mail Removed)>...
> in case it is not clear, i'm referring to the template you are using, which
> inherits control. When you develop templated controls, you should implement
> this interface InameingContainer to avoid naming conflicts on a page. . Your
> main class nested is un-necessarily implementing this interface as you
> already have clientID which is is unique, and you can name your table :
> clientID + "_table";
>
> "Alessandro Zifiglio" <(E-Mail Removed)> wrote in
> message news%rNb.3283$(E-Mail Removed)...
> > have your control implement INamingContainer. This will generate Unique

> Ids
> > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > news:(E-Mail Removed) m...
> > > Peter,
> > >
> > > Again, thanks for your on going help.
> > >
> > > I have been struggling with this problem for 3+ months and on someone
> > > else's advice purchased "Developing Microsoft ASP.NET Server Controls
> > > and Components". Following the book religiously, I started again from
> > > the "Hello World" example and worked forward to recreate my problem.
> > > Kothari & Datye's touches on controls "whose nested content does not
> > > correspond to properties" on pages 332-7, but the example provided is
> > > very trivial and doesn't address any of the issues I've encountered.
> > > If I've missed something, please point me to the section.
> > >
> > > My control uses the ParseChildrenAttribute attribute with the
> > > declaration '[ParseChildren(true, "NestedChild")', which defines a
> > > public property named 'NestedChild', with nested (child) elements
> > > corresponding to child elements of the 'NestedChild' property. The
> > > idea with the '_NestedChildren' property is to add each nested child
> > > element to a collection, which I can iterate through and hide or show
> > > based on additional conditions. I have extra logic here, which I have
> > > omitted for clarity.
> > >
> > > As you suggested, I have move my code to CreateChildControls. The
> > > control renders ok in design time, but fails in runtime at
> > > FillNamedControlsTable with the error message "Multiple controls with
> > > the same ID 'myControl1' were found. FindControl requires that
> > > controls have unique IDs". With the RequiredFieldValidator removed,
> > > the control renders but generates the same error with the buttons
> > > onClick event. Looking at the source code I notice that the command
> > > button has now rendered as:
> > >
> > > <input type="submit" name="myControl1:cmdTest1" value="Test"
> > > id="myControl1_cmdTest1" />
> > >
> > > I can't compile my code behind with an event handling
> > > myControl1_cmdTest1.Click, because the compiler is expecting
> > > cmdTest1.click.
> > >
> > > My code for CreateChildControls now looks like:
> > >
> > > protected override void CreateChildControls() {
> > >
> > > this.Controls.Clear();
> > > this.Controls.Add(new LiteralControl("<b>before</b><br /><hr><br
> > > />"));
> > >
> > > foreach (NestedChild child in _NestedChildren) {
> > > //this.Controls.Add(child);
> > >
> > > this.Controls.Add(new LiteralControl("* " + child.Caption +
> > > "<BR>"));
> > >
> > > // Display the contents of child in a single cell table
> > > HtmlTableCell td = new HtmlTableCell();
> > > td.Style.Add("width", "250px");
> > > td.Style.Add("height", "100px");
> > > td.Controls.Add(child);
> > >
> > > // Add the table cell to a new table row
> > > HtmlTableRow tr = new HtmlTableRow();
> > > tr.Controls.Add(td);
> > >
> > > // Add the table row to a new table
> > > HtmlTable table = new HtmlTable();
> > > table.ID = this.UniqueID;
> > > table.Width = this.Width.ToString();
> > > table.Height = this.Height.ToString();
> > > table.CellSpacing = 2;
> > > table.CellPadding = 2;
> > > table.Border = 1;
> > > table.Style.Add("background-color", "#C0C0C0");
> > > table.Controls.Add(tr);
> > >
> > > this.Controls.Add(table);
> > >
> > > }
> > > this.Controls.Add(new LiteralControl("<br /><hr><br
> > > /><b>after</b>"));
> > > }
> > >
> > > Any other suggestions?
> > >
> > > Regards,
> > >
> > > Stephen
> > >
> > >
> > > "Peter Blum" <(E-Mail Removed)> wrote in message

> news:<(E-Mail Removed)>...
> > > > I strongly encourage you to step back and learn the right way to build
> > > > custom controls. Otherwise, you will be developing code that may

> require
> > > > plenty more debugging and maintenance because it doesn't confirm to

> how
> > > > Microsoft designed web controls. I recommend the book "Developing

> ASP.NET
> > > > Server Controls and Components" from Microsoft Press.
> > > >
> > > > In your code, I do not understand why you have the _NestedChildren

> property.
> > > > The webcontrol framework automatically supports child controls using

> the
> > > > ParseChildrenAttribute. (See the .net docs on this attribute.) I do
> > > > understand what you are doing in CreateChildControls and that looks

> OK.
> > > >
> > > > Here are my recommendations.
> > > > - Move the code you have creating the table and its contents into
> > > > CreateChildControls without removing the existing code.
> > > > - Any "output.Write()" calls can become LiteralControl objects. (new
> > > > LiteralControl("<br>"))
> > > > - Add objects to the Controls collection on your control.
> > > >
> > > > Now your validators will be created before OnPreRender occurs. That

> allows
> > > > the webcontrol system that Microsoft designed to call each of your
> > > > validators own OnPreRender method properly, setting up many things

> that
> are
> > > > required for validation.
> > > >
> > > > --- Peter Blum
> > > > www.PeterBlum.com
> > > > Email: (E-Mail Removed)
> > > > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > > > news:(E-Mail Removed) m...
> > > > > Peter,
> > > > >
> > > > > I was under the mistaken impression that I was already overriding
> > > > > CreateChildControls to create the controls with the code:
> > > > >
> > > > > protected override void CreateChildControls() {
> > > > > this.Controls.Clear();
> > > > > foreach (NestedChild child in _NestedChildren) {
> > > > > this.Controls.Add(child);
> > > > > }
> > > > > }
> > > > >
> > > > > If I leave this override out then the control renders fine (with the
> > > > > RequiredFieldValidators) but fails to generate any server side

> events.
> > > > > Moving this code block to OnPreRender (with base.OnPreRend) after
> > > > > adding the controls doesn't seem to make any difference.
> > > > >
> > > > > I have also tried moving the code in the overridden Render method to
> > > > > the overridden RenderContents method. This doesn't appear to have

> made
> > > > > any difference.
> > > > >
> > > > > Have I missed the point? Could I beg you for some sample code?
> > > > >
> > > > > Thanks,
> > > > >
> > > > > Stephen
> > > > >
> > > > > "Peter Blum" <(E-Mail Removed)> wrote in message

> news:<(E-Mail Removed)>...
> > > > > > I think I see the problem. You are creating your control objects

> in
> the
> > > > > > Render method. Leave the Render method alone. Generally, only use

> it
> if
> you
> > > > > > wanted to output explicit HTML (although there are some cases

> where
> you
> can
> > > > > > do what you did.) Instead, create the controls in either the
> > > > > > CreateChildControls() or OnPreRender method.
> > > > > >
> > > > > > Here's the actual problem you are having. Validators must have

> their
> > > > > > OnPreRender method run. Because your validators aren't in this

> control's
> > > > > > Controls property, they don't get OnPreRender run. So move your

> code
> to
> > > > > > OnPreRender and call base.OnPreRender() after those controls are

> added
> to
> > > > > > the Controls property.
> > > > > >
> > > > > > --- Peter Blum
> > > > > > www.PeterBlum.com
> > > > > > Email: (E-Mail Removed)
> > > > > >
> > > > > > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > > > > > news:(E-Mail Removed) om...
> > > > > > > Peter,
> > > > > > >
> > > > > > > Thanks for the link. I have enjoyed looking at your site, but

> its
> not
> > > > > > > going to give me the answer I need. My control needs to be able

> to
> > > > > > > render any nested literal content the developer throws at it, so

> I
> > > > > > > have to resolve this problem with MS's validators.
> > > > > > >
> > > > > > > I have designed my control in such a way that it only needs to
> > > > > > > validate controls in the same naming container but as you noted,

> the
> > > > > > > error message seems to indicate that the control thinks the

> textbox
> > > > > > > and validator are in different containers.
> > > > > > >
> > > > > > > What I find particularly puzzling is that if I simple override

> the
> > > > > > > render method with 'base.Render(output)' the validator has not

> problem
> > > > > > > locating the textbox in the container. The problem only seems to

> arise
> > > > > > > when I attempt to encapsulate the controls in my own formatting

> with
> > > > > > > 'table.RenderControl(output)'.
> > > > > > >
> > > > > > > Should I be looking at overriding the 'table.RenderControl'

> method
> to
> > > > > > > make this work? If so what should I be doing?
> > > > > > >
> > > > > > > I recently found another commercial product that is able to do

> what
> > > > > > > I'm trying to achive
> > > > > > >

> (http://www.infragistics.com/products...sp?sec=0&cat=3)
> so I
> > > > > > > know it must be possible (... and I don't want to pay USD $500)
> > > > > > >
> > > > > > > Thanks,
> > > > > > >
> > > > > > > Stephen
> > > > > > >
> > > > > > >
> > > > > > >
> > > > > > > "Peter Blum" <(E-Mail Removed)> wrote in message

> news:<O#(E-Mail Removed)>...
> > > > > > > > The ControlToValidate property only accepts the ID of another
> > > > control in
> > > > the
> > > > > > > > same naming container. I believe that this error is due to

> naming
> container
> > > > > > > > problems. While your code seems to enclose both the textbox

> and
> validator
> > > > > > > > within the same naming container, the error message says

> otherwise.
> > > > > > > >
> > > > > > > > FYI: If the naming container is indeed the problem, I have a

> commercial
> > > > > > > > product that replaces Microsoft's validators to overcome its

> many
> > > > > > > > limitations. My validators support controls in any naming

> container.
> The
> > > > > > > > product is "Professional Validation And More". Details are at
> > > > > > > > http://www.peterblum.com/vam/home.aspx.
> > > > > > > >
> > > > > > > > --- Peter Blum
> > > > > > > > www.PeterBlum.com
> > > > > > > > Email: (E-Mail Removed)
> > > > > > > >
> > > > > > > > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > > > > > > > news:(E-Mail Removed) om...
> > > > > > > > > Gurus,
> > > > > > > > >
> > > > > > > > > I have a custom web control that in turn has nested child

> controls. I
> > > > > > > > > want to be able to encapsulated and render any literal HTML

> and or
> > > > > > > > > server controls placed between the child control's tags.

> This
> works
> > > > > > > > > fine, unless I add a RequiredFieldValidator control at which

> point
> my
> > > > > > > > > aspx page fails at

> 'WebControls.BaseValidator.CheckControlValidationP roperty'
> > > > > > > > > with the error message 'Unable to find control id 'TextBox1'
> > > > > > > > > referenced by the 'ControlToValidate' property of
> > > > > > > > > 'RequiredFieldValidator1'.
> > > > > > > > >
> > > > > > > > > My control 'Nested' contains a collection of 'NestedChild'

> controls
> > > > > > > > > with a simple 'Caption' property. I override the 'Render'

> method
> on
> > > > > > > > > the 'Nested' control and iterate though each NestedChild' in

> the
> > > > > > > > > collection, outputting the child's literal content to a

> formatted
> > > > > > > > > table.
> > > > > > > > >
> > > > > > > > > The full code for my control is (please cut-n-paste to

> replicate
> my
> > > > > > > > > problem):
> > > > > > > > >
> > > > > > > > > using System;
> > > > > > > > > using System.Web.UI;
> > > > > > > > > using System.Web.UI.WebControls;
> > > > > > > > > using System.ComponentModel;
> > > > > > > > > using System.Collections;
> > > > > > > > > using System.Collections.Specialized;
> > > > > > > > > using System.Web.UI.HtmlControls;
> > > > > > > > >
> > > > > > > > > namespace Custom.Web.UI {
> > > > > > > > >
> > > > > > > > > [ToolboxData("<{0}:Nested runat=server></{0}:Nested2>")]
> > > > > > > > > [ParseChildren(true, "NestedChild"),

> PersistChildren(false)]
> > > > > > > > > public class Nested : WebControl, INamingContainer,
> > > > > > > > > IPostBackDataHandler {
> > > > > > > > >
> > > > > > > > > private NestedChildCollection _NestedChildren = new
> > > > > > > > > NestedChildCollection();
> > > > > > > > >
> > > > > > > > > #region Properties
> > > > > > > > > [
> > > > > > > > >
> > > > > > > >
> > > > > >
> > > >

> DesignerSerializationVisibility(DesignerSerializat ionVisibility.Content),
> > > > > > > > > PersistenceMode(PersistenceMode.InnerDefaultProper ty),
> > > > > > > > > Description("A collection of nested children"),
> > > > > > > > > ]
> > > > > > > > > public NestedChildCollection NestedChild {
> > > > > > > > > get{ return _NestedChildren; }
> > > > > > > > > }
> > > > > > > > > #endregion
> > > > > > > > >
> > > > > > > > > #region Overrides
> > > > > > > > >
> > > > > > > > > protected override void CreateChildControls() {
> > > > > > > > > this.Controls.Clear();
> > > > > > > > > foreach (NestedChild child in _NestedChildren) {
> > > > > > > > > this.Controls.Add(child);
> > > > > > > > > }
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > protected override void Render(HtmlTextWriter output) {
> > > > > > > > > output.Write("<b>before</b><br /><hr><br />");
> > > > > > > > > //base.Render(output);
> > > > > > > > > foreach(NestedChild child in _NestedChildren) {
> > > > > > > > > output.Write("* " + child.Caption + "<BR>");
> > > > > > > > >
> > > > > > > > > // Display the literal contents of NestedChild
> > > > > > > > > // in a single table cell
> > > > > > > > > HtmlTableCell td = new HtmlTableCell();
> > > > > > > > > td.Controls.Add(child);
> > > > > > > > >
> > > > > > > > > // Add the table cell to a new table row
> > > > > > > > > HtmlTableRow tr = new HtmlTableRow();
> > > > > > > > > tr.Controls.Add(td);
> > > > > > > > >
> > > > > > > > > // Add the table row to a new table
> > > > > > > > > HtmlTable table = new HtmlTable();
> > > > > > > > > table.ID = this.UniqueID;
> > > > > > > > > table.CellSpacing = 2;
> > > > > > > > > table.CellPadding = 2;
> > > > > > > > > table.Border = 1;
> > > > > > > > > table.Style.Add("background-color", "#C0C0C0");
> > > > > > > > > table.Controls.Add(tr);
> > > > > > > > >
> > > > > > > > > /* FAILS NEXT LINE
> > > > > > > > > Error: "Unable to find control id 'txtTest1'

> referenced
> > > > > > > > > by the 'ControlToValidate' property of 'valTest1'"
> > > > > > > > > /*
> > > > > > > > > table.RenderControl(output);
> > > > > > > > > }
> > > > > > > > > output.Write("<br /><hr><br /><b>after</b>");
> > > > > > > > > }
> > > > > > > > > #endregion
> > > > > > > > >
> > > > > > > > > #region Implements IPostBackDataHandler (postback only)
> > > > > > > > > bool IPostBackDataHandler.LoadPostData(string

> strPostDataKey,
> > > > > > > > > NameValueCollection postDataCollection) {
> > > > > > > > > return true;
> > > > > > > > > }
> > > > > > > > > void IPostBackDataHandler.RaisePostDataChangedEvent() {}
> > > > > > > > > #endregion
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > [ToolboxItem(false), DefaultProperty("Caption")]
> > > > > > > > > public class NestedChild : Control{
> > > > > > > > > private String m_strCaption;
> > > > > > > > > public String Caption {
> > > > > > > > > get { return m_strCaption; }
> > > > > > > > > set { m_strCaption = value; }
> > > > > > > > > }
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public class NestedChildCollection : CollectionBase {
> > > > > > > > >
> > > > > > > > > public NestedChild this[int nIndex]{
> > > > > > > > > get { return (NestedChild) base.List[nIndex]; }
> > > > > > > > > }
> > > > > > > > > public void Add(NestedChild child){
> > > > > > > > > base.List.Add(child);
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public int IndexOf(NestedChild child){
> > > > > > > > > return base.List.IndexOf(child);
> > > > > > > > > }
> > > > > > > > > }
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > When deployed the aspx page looks like:
> > > > > > > > >
> > > > > > > > > <form id="Form1" method="post" runat="server">
> > > > > > > > > <P>Nested Control</P>
> > > > > > > > > <P>
> > > > > > > > > <cc1:Nested id="Nested1" runat="server">
> > > > > > > > > <cc1:NestedChild Caption="NestedChild">
> > > > > > > > > <asp:Button id="cmdTest" runat="server" Text="Generate
> > > > > > > > > Event"></asp:Button>
> > > > > > > > > <asp:TextBox id="txtTest" runat="server"></asp:TextBox>
> > > > > > > > > <asp:RequiredFieldValidator id="valTest" runat="server"
> > > > > > > > > ControlToValidate="txtTest"
> > > > > > > > > ErrorMessage="This field is
> > > > > > > > > Required.">*</asp:RequiredFieldValidator>
> > > > > > > > > </cc1:NestedChild>
> > > > > > > > > </cc1:Nested2></P>
> > > > > > > > > <P>&nbsp;</P>
> > > > > > > > > <P>
> > > > > > > > > <asp:label id="lblResult"

> runat="server">lblResult</asp:label></P>
> > > > > > > > > </form>
> > > > > > > > >
> > > > > > > > > If I remove 'RequiredFieldValidator' my control render as

> expected.
> > > > > > > > >
> > > > > > > > > I have noticed, that If I replace the entire formatting

> logic
> in
> the
> > > > > > > > > 'Render' method with a call to 'base.Render(output);', the
> > > > > > > > > RequiredFieldValidator works as expected.
> > > > > > > > >
> > > > > > > > > I think this is quite a technical problem and I assume that
> > > > > > > > > 'table.RenderControl(output)' is not preforming the

> necessary
> > > > > > > > > server-side pre-validation to pass a

> 'RequiredFieldValidator'.
> How
> can
> > > > > > > > > I do this?
> > > > > > > > >
> > > > > > > > > Regards,
> > > > > > > > >
> > > > > > > > > Stephen

> >
> >

 
Reply With Quote
 
Alessandro Zifiglio
Guest
Posts: n/a
 
      01-17-2004
Now that the naming issue has been resolved by PeterBlum --your second
problem is the events being fired in your nestedchild controls. For any
events that fire in your template(nestedchild) you need to bubble them up to
the container(nested), you can then either take action in nested if this is
the last destination or bubble them futher up to the page, that is the
container of nested.

to handle or to raise the bubbled event, you must override the OnBubbleEvent
method for your control.

Now always building up on the same code you posted --the first one that is,
you have a button in your template --the clickevent for the button will fire
in your template --override the OnBubbleEvent method there and have it fire
in the container "nested" --in nested override the OnBUbbleEvent again and
send it up to its container(the page where the control sits)
You do not need to implement the IPostBackEventHandler for this. There is a
very nice example on msdn which goes into all the details. However its very
vast so i'm coping out the steps you need to take. For more look at the
example to which i'm including the link after the code below :
//First bubble events in NestedChildCollection
//Note how it looks only for a CommandEventArgs
//and passes that information to the
//class TemplatedListCommandEventArgs which will in turn delegate
//the event.
public class NestedChildCollection : CollectionBase {

public NestedChild this[int nIndex]{
get { return (NestedChild) base.List[nIndex]; }
}
public void Add(NestedChild child){
base.List.Add(child);
}

public int IndexOf(NestedChild child){
return base.List.IndexOf(child);
}
}

protected override bool OnBubbleEvent(object source, EventArgs e) {
if (e is CommandEventArgs) {
// Add the information about Item to CommandEvent.

TemplatedListCommandEventArgs args =
new TemplatedListCommandEventArgs(this, source,
(CommandEventArgs)e);

RaiseBubbleEvent(this, args);
return true;
}
return false;
}

}


//Now the class TemplatedListCommandEventArgs --this is where we passed the
captured event, and now we delegate it.

public sealed class TemplatedListCommandEventArgs : CommandEventArgs {

private TemplatedListItem item;
private object commandSource;

public TemplatedListCommandEventArgs(TemplatedListItem item, object
commandSource, CommandEventArgs originalArgs) :
base(originalArgs) {
this.item = item;
this.commandSource = commandSource;
}

public TemplatedListItem Item {
get {
return item;
}
}

public object CommandSource {
get {
return commandSource;
}
}
}

public delegate void TemplatedListCommandEventHandler(object source,
TemplatedListCommandEventArgs e);


//now in your class(nested) first Override OnBubbleEvent method and
//bubble the events to the container(that is the page the control sits)




//note how OnItemCommand is called when the TemplatedListCommandEventHandler
//is the one that fired --the one that we bubbled
//in the Template

protected override bool OnBubbleEvent(object source, EventArgs e) {
// Handle events raised by children by overriding OnBubbleEvent.

bool handled = false;

if (e is TemplatedListCommandEventArgs) {
TemplatedListCommandEventArgs ce =
(TemplatedListCommandEventArgs)e;

OnItemCommand(ce);
handled = true;
}

return handled;
}

//now the OnItemCommand --the one that we called in the above method :
//this will raise the bubbled Event to the client with
//the handler and all

protected virtual void OnItemCommand(TemplatedListCommandEventArgs e) {
TemplatedListCommandEventHandler onItemCommandHandler =
(TemplatedListCommandEventHandler)Events[EventItemCommand];
if (onItemCommandHandler != null) onItemCommandHandler(this, e);
}


//expose the handler TemplatedListCommandEventHandler to the client(the
page)

[
Category("Action"),
Description("Raised when a CommandEvent occurs within the
Template.")
]
public event TemplatedListCommandEventHandler ItemCommand {
add {
Events.AddHandler(EventItemCommand, value);
}
remove {
Events.RemoveHandler(EventItemCommand, value);
}
}



------------------------------------------------------Finish----------------
--------------------------------------

now in your page where the control sits you have the event handler use it,
all events fired in your templates can be captured here --you now have one
unique place to search for events as it is with templated controls, you can
have many controls in there that fire events, and you do not want an event
handler for every control in there, instead you want ONE handler that will
handle all --the trick it is to use the commandName for your buttons and
then look for this command name here --that way you can differentiate
between buttons and take action accordingly. So on the button that you have
used in your template pass use the CommandName property to like say if you
set the CommandName="save" then you can check if the save button was the one
clicked, see code below :

protected void MyList_ItemCreated(object sender, TemplatedListItemEventArgs
e) {

if (e.CommandName == "save"){
response.write("save button was clicked, lets do something")
}

}

This is the templated databound sample, surely you will learn a lot besides
the event bubbling ;P
Ok --please look at the sample code on MSDN.

If you have the docs then the link is :
ms-help://MS.VSCC/MS.MSDNVS/cpguide/html/cpcontemplateddataboundcontrolsampl
e.htm

http://msdn.microsoft.com/library/de...trolsample.asp

Not very hard to follow once you get a hang of it





"Peter Blum" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> Right now you're dealing with the ID property, as the error message tells
> you.
>
> If you do not assign an ID property, ASP.NET will automatically assign one
> for your. However, if you need to refer to that ID in some other control,
> like in Validator.ControlToValidator, that doesn't help.
>
> I don't see your code that creates the validators and textboxes. So I

don't
> know how you are assigning Ids there. But I can see how you are assigning
> the ID to the table. Perhaps we can learn from that:
> HtmlTable table = new HtmlTable();
> table.ID = this.UniqueID;
>
>
> Don't assign an ID to either UniqueID or ClientID properties. The ID

should
> be a unique name within the naming container. ASP.NET will convert it into

a
> unique ID in ClientID and UniqueID. Additionally, UniqueID introduces a
> format that doesn't work well in the client ID side attribute. (When you

see
> the HTML <input type='text' id=[from ClientID] name=[from UniqueID] />)
>
> Here's what I like to do for IDs of child controls within a custom

control.
> Use the ID of custom control + "_" + some name.
> For example:
> HtmlTable table = new HtmlTable();
> table.ID = this.ID + "_Table";
>
> Because your custom control's ID will already be unique within the naming
> container, so will its child controls.
>
> --- Peter Blum
> www.PeterBlum.com
> Email: (E-Mail Removed)
>
> "Stephen Miller" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed) m...
> > Peter,
> >
> > Again, thanks for your on going help.
> >
> > I have been struggling with this problem for 3+ months and on someone
> > else's advice purchased "Developing Microsoft ASP.NET Server Controls
> > and Components". Following the book religiously, I started again from
> > the "Hello World" example and worked forward to recreate my problem.
> > Kothari & Datye's touches on controls "whose nested content does not
> > correspond to properties" on pages 332-7, but the example provided is
> > very trivial and doesn't address any of the issues I've encountered.
> > If I've missed something, please point me to the section.
> >
> > My control uses the ParseChildrenAttribute attribute with the
> > declaration '[ParseChildren(true, "NestedChild")', which defines a
> > public property named 'NestedChild', with nested (child) elements
> > corresponding to child elements of the 'NestedChild' property. The
> > idea with the '_NestedChildren' property is to add each nested child
> > element to a collection, which I can iterate through and hide or show
> > based on additional conditions. I have extra logic here, which I have
> > omitted for clarity.
> >
> > As you suggested, I have move my code to CreateChildControls. The
> > control renders ok in design time, but fails in runtime at
> > FillNamedControlsTable with the error message "Multiple controls with
> > the same ID 'myControl1' were found. FindControl requires that
> > controls have unique IDs". With the RequiredFieldValidator removed,
> > the control renders but generates the same error with the buttons
> > onClick event. Looking at the source code I notice that the command
> > button has now rendered as:
> >
> > <input type="submit" name="myControl1:cmdTest1" value="Test"
> > id="myControl1_cmdTest1" />
> >
> > I can't compile my code behind with an event handling
> > myControl1_cmdTest1.Click, because the compiler is expecting
> > cmdTest1.click.
> >
> > My code for CreateChildControls now looks like:
> >
> > protected override void CreateChildControls() {
> >
> > this.Controls.Clear();
> > this.Controls.Add(new LiteralControl("<b>before</b><br /><hr><br
> > />"));
> >
> > foreach (NestedChild child in _NestedChildren) {
> > //this.Controls.Add(child);
> >
> > this.Controls.Add(new LiteralControl("* " + child.Caption +
> > "<BR>"));
> >
> > // Display the contents of child in a single cell table
> > HtmlTableCell td = new HtmlTableCell();
> > td.Style.Add("width", "250px");
> > td.Style.Add("height", "100px");
> > td.Controls.Add(child);
> >
> > // Add the table cell to a new table row
> > HtmlTableRow tr = new HtmlTableRow();
> > tr.Controls.Add(td);
> >
> > // Add the table row to a new table
> > HtmlTable table = new HtmlTable();
> > table.ID = this.UniqueID;
> > table.Width = this.Width.ToString();
> > table.Height = this.Height.ToString();
> > table.CellSpacing = 2;
> > table.CellPadding = 2;
> > table.Border = 1;
> > table.Style.Add("background-color", "#C0C0C0");
> > table.Controls.Add(tr);
> >
> > this.Controls.Add(table);
> >
> > }
> > this.Controls.Add(new LiteralControl("<br /><hr><br
> > /><b>after</b>"));
> > }
> >
> > Any other suggestions?
> >
> > Regards,
> >
> > Stephen
> >

>
>



 
Reply With Quote
 
Alessandro Zifiglio
Guest
Posts: n/a
 
      01-19-2004
Stephen, when I made that last post, I was in a hurry and missed out a few
things. I have given the code another look and here are some corrections.
However note that I have not taken the time to test this with your code, but
that i have just copied and pasted the essential parts that you need to
implement, and I have tried to adapt it to your code.

Also note that the example on MSDN if you tried to compile it along with its
designer class --you will end up with errors, this is because there are
numerous bugs in the code and i had to make many corrections before i was
able to run that code myself --however it demonstrates how to code and puts
you in the right direction on many techniques like with using
templates --databinding --associating a designer to your control, event
bubbling etc

Here is a much better step by step --the one i did last I missed out a few
things like declaring the static event EventItemCommand as object and i
removed some un-necessary code --Still did not test --the rest is up to you
to get this working

//First bubble events in NestedChildCollection
//Note how it looks only for a CommandEventArgs
//and passes that information to the
//class TemplatedListCommandEventArgs which will in turn delegate
//the event.
public class NestedChildCollection : CollectionBase {

public NestedChild this[int nIndex]{
get { return (NestedChild) base.List[nIndex]; }
}
public void Add(NestedChild child){
base.List.Add(child);
}

public int IndexOf(NestedChild child){
return base.List.IndexOf(child);
}
}

protected override bool OnBubbleEvent(object source, EventArgs e) {
if (e is CommandEventArgs) {
// Add the information about Item to CommandEvent.

TemplatedListCommandEventArgs args =
new TemplatedListCommandEventArgs(this, source,
(CommandEventArgs)e);

RaiseBubbleEvent(this, args);
return true;
}
return false;
}

}


//Now the class TemplatedListCommandEventArgs --this is where we passed the
captured event, and now we delegate it.

public sealed class TemplatedListCommandEventArgs : CommandEventArgs {
private NestedChildCollection item;
private object commandSource;

public TemplatedListCommandEventArgs(NestedChildCollectio n item,
object
commandSource, CommandEventArgs originalArgs) :
base(originalArgs) {
this.item = item;
this.commandSource = commandSource;
}


public object CommandSource {
get {
return commandSource;
}
}
}

public delegate void TemplatedListCommandEventHandler(object source,
TemplatedListCommandEventArgs e);


//now in your class(nested) first declare the static event variable
EventItemCommand as object
//Next Override OnBubbleEvent method and
//bubble the events to the container(that is the page the control sits)

private static readonly object EventItemCommand = new object();



//note how OnItemCommand is called when the TemplatedListCommandEventHandler
//is the one that fired --the one that we bubbled
//in the Template

protected override bool OnBubbleEvent(object source, EventArgs e) {
// Handle events raised by children by overriding OnBubbleEvent.

bool handled = false;

if (e is TemplatedListCommandEventArgs) {
TemplatedListCommandEventArgs ce =
(TemplatedListCommandEventArgs)e;

OnItemCommand(ce);
handled = true;
}

return handled;
}

//now the OnItemCommand --the one that we called in the above method :
//this will raise the bubbled Event to the client with
//the handler and all

protected virtual void OnItemCommand(TemplatedListCommandEventArgs e) {
TemplatedListCommandEventHandler onItemCommandHandler =
(TemplatedListCommandEventHandler)Events[EventItemCommand];
if (onItemCommandHandler != null) onItemCommandHandler(this, e);
}


//expose the handler TemplatedListCommandEventHandler to the client(the
page)

[
Category("Action"),
Description("Raised when a CommandEvent occurs within the
Template.")
]
public event TemplatedListCommandEventHandler ItemCommand {
add {
Events.AddHandler(EventItemCommand, value);
}
remove {
Events.RemoveHandler(EventItemCommand, value);
}
}



------------------------------------------------------Finish----------------
--------------------------------------


protected void MyList_ItemCreated(object sender,
TemplatedListCommandEventArgs e) {
if (e.CommandName == "save"){
response.write("save button was clicked, lets do something")
}

}


"Alessandro Zifiglio" <(E-Mail Removed)> wrote in
message news:l_bOb.4409$(E-Mail Removed)...
> Now that the naming issue has been resolved by PeterBlum --your second
> problem is the events being fired in your nestedchild controls. For any
> events that fire in your template(nestedchild) you need to bubble them up

to
> the container(nested), you can then either take action in nested if this

is
> the last destination or bubble them futher up to the page, that is the
> container of nested.
>
> to handle or to raise the bubbled event, you must override the

OnBubbleEvent
> method for your control.
>
> Now always building up on the same code you posted --the first one that

is,
> you have a button in your template --the clickevent for the button will

fire
> in your template --override the OnBubbleEvent method there and have it

fire
> in the container "nested" --in nested override the OnBUbbleEvent again and
> send it up to its container(the page where the control sits)
> You do not need to implement the IPostBackEventHandler for this. There is

a
> very nice example on msdn which goes into all the details. However its

very
> vast so i'm coping out the steps you need to take. For more look at the
> example to which i'm including the link after the code below :
> //First bubble events in NestedChildCollection
> //Note how it looks only for a CommandEventArgs
> //and passes that information to the
> //class TemplatedListCommandEventArgs which will in turn delegate
> //the event.
> public class NestedChildCollection : CollectionBase {
>
> public NestedChild this[int nIndex]{
> get { return (NestedChild) base.List[nIndex]; }
> }
> public void Add(NestedChild child){
> base.List.Add(child);
> }
>
> public int IndexOf(NestedChild child){
> return base.List.IndexOf(child);
> }
> }
>
> protected override bool OnBubbleEvent(object source, EventArgs e) {
> if (e is CommandEventArgs) {
> // Add the information about Item to CommandEvent.
>
> TemplatedListCommandEventArgs args =
> new TemplatedListCommandEventArgs(this, source,
> (CommandEventArgs)e);
>
> RaiseBubbleEvent(this, args);
> return true;
> }
> return false;
> }
>
> }
>
>
> //Now the class TemplatedListCommandEventArgs --this is where we passed

the
> captured event, and now we delegate it.
>
> public sealed class TemplatedListCommandEventArgs : CommandEventArgs {
>
> private TemplatedListItem item;
> private object commandSource;
>
> public TemplatedListCommandEventArgs(TemplatedListItem item,

object
> commandSource, CommandEventArgs originalArgs) :
> base(originalArgs) {
> this.item = item;
> this.commandSource = commandSource;
> }
>
> public TemplatedListItem Item {
> get {
> return item;
> }
> }
>
> public object CommandSource {
> get {
> return commandSource;
> }
> }
> }
>
> public delegate void TemplatedListCommandEventHandler(object source,
> TemplatedListCommandEventArgs e);
>
>
> //now in your class(nested) first Override OnBubbleEvent method and
> //bubble the events to the container(that is the page the control sits)
>
>
>
>
> //note how OnItemCommand is called when the

TemplatedListCommandEventHandler
> //is the one that fired --the one that we bubbled
> //in the Template
>
> protected override bool OnBubbleEvent(object source, EventArgs e) {
> // Handle events raised by children by overriding

OnBubbleEvent.
>
> bool handled = false;
>
> if (e is TemplatedListCommandEventArgs) {
> TemplatedListCommandEventArgs ce =
> (TemplatedListCommandEventArgs)e;
>
> OnItemCommand(ce);
> handled = true;
> }
>
> return handled;
> }
>
> //now the OnItemCommand --the one that we called in the above method :
> //this will raise the bubbled Event to the client with
> //the handler and all
>
> protected virtual void OnItemCommand(TemplatedListCommandEventArgs e) {
> TemplatedListCommandEventHandler onItemCommandHandler =
> (TemplatedListCommandEventHandler)Events[EventItemCommand];
> if (onItemCommandHandler != null) onItemCommandHandler(this,

e);
> }
>
>
> //expose the handler TemplatedListCommandEventHandler to the client(the
> page)
>
> [
> Category("Action"),
> Description("Raised when a CommandEvent occurs within the
> Template.")
> ]
> public event TemplatedListCommandEventHandler ItemCommand {
> add {
> Events.AddHandler(EventItemCommand, value);
> }
> remove {
> Events.RemoveHandler(EventItemCommand, value);
> }
> }
>
>
>
> ------------------------------------------------------Finish--------------

--
> --------------------------------------
>
> now in your page where the control sits you have the event handler use it,
> all events fired in your templates can be captured here --you now have one
> unique place to search for events as it is with templated controls, you

can
> have many controls in there that fire events, and you do not want an event
> handler for every control in there, instead you want ONE handler that will
> handle all --the trick it is to use the commandName for your buttons and
> then look for this command name here --that way you can differentiate
> between buttons and take action accordingly. So on the button that you

have
> used in your template pass use the CommandName property to like say if you
> set the CommandName="save" then you can check if the save button was the

one
> clicked, see code below :
>
> protected void MyList_ItemCreated(object sender,

TemplatedListItemEventArgs
> e) {
>
> if (e.CommandName == "save"){
> response.write("save button was clicked, lets do something")
> }
>
> }
>
> This is the templated databound sample, surely you will learn a lot

besides
> the event bubbling ;P
> Ok --please look at the sample code on MSDN.
>
> If you have the docs then the link is :
>

ms-help://MS.VSCC/MS.MSDNVS/cpguide/html/cpcontemplateddataboundcontrolsampl
> e.htm
>
>

http://msdn.microsoft.com/library/de...trolsample.asp
>
> Not very hard to follow once you get a hang of it
>
>
>
>
>
> "Peter Blum" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
> > Right now you're dealing with the ID property, as the error message

tells
> > you.
> >
> > If you do not assign an ID property, ASP.NET will automatically assign

one
> > for your. However, if you need to refer to that ID in some other

control,
> > like in Validator.ControlToValidator, that doesn't help.
> >
> > I don't see your code that creates the validators and textboxes. So I

> don't
> > know how you are assigning Ids there. But I can see how you are

assigning
> > the ID to the table. Perhaps we can learn from that:
> > HtmlTable table = new HtmlTable();
> > table.ID = this.UniqueID;
> >
> >
> > Don't assign an ID to either UniqueID or ClientID properties. The ID

> should
> > be a unique name within the naming container. ASP.NET will convert it

into
> a
> > unique ID in ClientID and UniqueID. Additionally, UniqueID introduces a
> > format that doesn't work well in the client ID side attribute. (When you

> see
> > the HTML <input type='text' id=[from ClientID] name=[from UniqueID] />)
> >
> > Here's what I like to do for IDs of child controls within a custom

> control.
> > Use the ID of custom control + "_" + some name.
> > For example:
> > HtmlTable table = new HtmlTable();
> > table.ID = this.ID + "_Table";
> >
> > Because your custom control's ID will already be unique within the

naming
> > container, so will its child controls.
> >
> > --- Peter Blum
> > www.PeterBlum.com
> > Email: (E-Mail Removed)
> >
> > "Stephen Miller" <(E-Mail Removed)> wrote in message
> > news:(E-Mail Removed) m...
> > > Peter,
> > >
> > > Again, thanks for your on going help.
> > >
> > > I have been struggling with this problem for 3+ months and on someone
> > > else's advice purchased "Developing Microsoft ASP.NET Server Controls
> > > and Components". Following the book religiously, I started again from
> > > the "Hello World" example and worked forward to recreate my problem.
> > > Kothari & Datye's touches on controls "whose nested content does not
> > > correspond to properties" on pages 332-7, but the example provided is
> > > very trivial and doesn't address any of the issues I've encountered.
> > > If I've missed something, please point me to the section.
> > >
> > > My control uses the ParseChildrenAttribute attribute with the
> > > declaration '[ParseChildren(true, "NestedChild")', which defines a
> > > public property named 'NestedChild', with nested (child) elements
> > > corresponding to child elements of the 'NestedChild' property. The
> > > idea with the '_NestedChildren' property is to add each nested child
> > > element to a collection, which I can iterate through and hide or show
> > > based on additional conditions. I have extra logic here, which I have
> > > omitted for clarity.
> > >
> > > As you suggested, I have move my code to CreateChildControls. The
> > > control renders ok in design time, but fails in runtime at
> > > FillNamedControlsTable with the error message "Multiple controls with
> > > the same ID 'myControl1' were found. FindControl requires that
> > > controls have unique IDs". With the RequiredFieldValidator removed,
> > > the control renders but generates the same error with the buttons
> > > onClick event. Looking at the source code I notice that the command
> > > button has now rendered as:
> > >
> > > <input type="submit" name="myControl1:cmdTest1" value="Test"
> > > id="myControl1_cmdTest1" />
> > >
> > > I can't compile my code behind with an event handling
> > > myControl1_cmdTest1.Click, because the compiler is expecting
> > > cmdTest1.click.
> > >
> > > My code for CreateChildControls now looks like:
> > >
> > > protected override void CreateChildControls() {
> > >
> > > this.Controls.Clear();
> > > this.Controls.Add(new LiteralControl("<b>before</b><br /><hr><br
> > > />"));
> > >
> > > foreach (NestedChild child in _NestedChildren) {
> > > //this.Controls.Add(child);
> > >
> > > this.Controls.Add(new LiteralControl("* " + child.Caption +
> > > "<BR>"));
> > >
> > > // Display the contents of child in a single cell table
> > > HtmlTableCell td = new HtmlTableCell();
> > > td.Style.Add("width", "250px");
> > > td.Style.Add("height", "100px");
> > > td.Controls.Add(child);
> > >
> > > // Add the table cell to a new table row
> > > HtmlTableRow tr = new HtmlTableRow();
> > > tr.Controls.Add(td);
> > >
> > > // Add the table row to a new table
> > > HtmlTable table = new HtmlTable();
> > > table.ID = this.UniqueID;
> > > table.Width = this.Width.ToString();
> > > table.Height = this.Height.ToString();
> > > table.CellSpacing = 2;
> > > table.CellPadding = 2;
> > > table.Border = 1;
> > > table.Style.Add("background-color", "#C0C0C0");
> > > table.Controls.Add(tr);
> > >
> > > this.Controls.Add(table);
> > >
> > > }
> > > this.Controls.Add(new LiteralControl("<br /><hr><br
> > > /><b>after</b>"));
> > > }
> > >
> > > Any other suggestions?
> > >
> > > Regards,
> > >
> > > Stephen
> > >

> >
> >

>
>



 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Skins disappear when overriding Render method John ASP .Net 0 08-28-2006 02:59 PM
JSP Custom Tags as attribute values for other custom tags Dave Java 0 08-14-2006 02:21 PM
Ignore literal content when parsing custom control children? Donal McWeeney ASP .Net Building Controls 2 09-06-2004 08:10 AM
Overriding ImageButton Render in a custom control Peter Colson ASP .Net Web Controls 3 11-18-2003 11:33 PM
Custom Tags within Custom Tags. Ranganath Java 2 10-21-2003 06:14 AM



Advertisments