Page inheritance detaches validation script

T

Tim Colton

I have a web form which has a textbox, required field validator, and a submit button. If the web form inherits from System.Web.UI.Page everything works as expected. If you leave the textbox blank and click on the button, the client-side validation code runs, displays the error text and prevents the postback

If the page inherits from a intermediate class the validation code does not run. The intermediate class inherits from System.Web.UI.Page. In the class I wrap the contents of the web form HTML control with a panel control using the following code

//Surround the existing content with a pane
foreach (Control currentControl in Page.Controls

if (currentControl.GetType().ToString() == "System.Web.UI.HtmlControls.HtmlForm"

//Move the existing controls to a panel; this process "breaks" the client-sid
//validation. The input button no longer calls the client-side validation script
Panel myPanel = new Panel()
while (currentControl.Controls.Count > 0

myPanel.Controls.Add(currentControl.Controls[0])


//Attach the panel to the current contro
currentControl.Controls.Add(myPanel)



When I compare the browser HTML source the difference between the working and non-working scenarios involves the onclick attribute of the button. In the non-working case, there is no onclick attribute pointing to the validation javascript
The validation script is there; it's just not "wired up" to the button

How (or when) does the onclick attribute get set? Do I need to do something to get the proper onclick attribute? Thanks in advance for suggestions.
 
J

Jeffrey Tan[MSFT]

Hi tcskier,

Based on my understanding, you apply an intermediate page class for other
class to inherit, but your validation does not work.

If the senario is just as you stated, only the submit button missed the
onclick attribute for the client validation, I think you can just add it
like this:

First get that submit button's reference, then:

bt.Attributes.Add("onclick","validation function's name");

This will render onclick attribute for the submit button "bt";

==============================
Please apply my suggestion above and let me know if it helps resolve your
problem.

Thank you for your patience and cooperation. If you have any questions or
concerns, please feel free to post it in the group. I am standing by to be
of assistance.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
T

Tim Colton

Although the method you suggest is a workaround, I still do not understand why the problem occurs. Simply inserting a panel control in the object hierarchy of the page shouldn't break the functionality of individual controls

The purpose of the intermediate class is to add graphics and navigation controls to every page in a web site. Since the content will vary from page to page, I do not want to have to scan the object collection looking for buttons so that I can "manually" add the onclick attribute

Furthermore, the validation code can be triggered by controls other than buttons. For example, you can have a textbox with autopostback which has an associated regular expression validator. When someone types in the textbox, and then hits the enter key, client side validation occurs before the postback

I just tried this scenario with and without my intermediate class. If the web form inherits from the System.Web.UI.Page the validation occurs as expected. When the web form inherits from my intermediate class, no validation occurs. This situtation is really odd because the validation code is tied to the Form object. In both cases the validation code is properly set up. It just doesn't work in the second scenario (when inheriting from the intermediate class)

In looking at the javascript in the browser source and in the webUIValidation.js file, it looks like the code recursively walks through the controls on the page. I wonder if this could be part of the problem. Perhaps when the code encounters the "div" tag (which is what the panel object gets rendered to) it exits the code early and the validation controls do not get set up properly

-Tim
 
J

Jeffrey Tan[MSFT]

Hi Tim,

Thanks very much for your feedback.

I see your concern.

Yes, I have reproduced out your problem. Actually, this problem is not
becaused of whether the page is inherited, but because of you changed the
control tree improperly.

To prove my point, this code snippet also has the same problem as you:

public class WebForm1 : Page
{

protected System.Web.UI.HtmlControls.HtmlForm Form1;
private void Page_Load(object sender, System.EventArgs e)
{
foreach (Control currentControl in Page.Controls)
{
if (currentControl.GetType().ToString() ==
"System.Web.UI.HtmlControls.HtmlForm")
{
//Move the existing controls to a panel; this process "breaks" the
client-side
//validation. The input button no longer calls the client-side
validation script.
Panel myPanel = new Panel();

while (currentControl.Controls.Count > 0)
{
myPanel.Controls.Add(currentControl.Controls[0]);
}

currentControl.Controls.Add(myPanel);
}
}
}
}

As you can see, in Page_load event, you changed the original control tree,
so the Asp.net will not generate the correct html at client side.

Actually, you are not recommanded to move the control tree dynamically at
server side. You should only add or remove the control in the Control tree.

Can not you add the controls to the Panel at design-time? Why you have to
add them at run-time? If you can explain your senario more clearly, I may
find a workaround for you.

Thank you for your patience and cooperation. If you have any questions or
concerns, please feel free to post it in the group. I am standing by to be
of assistance.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
F

Fred Hirschfeld

I created an intermediate page for my code as well and needed that area to
generate all the header, left navigation and footer parts of the page
without having to interfere with the page content on derived pages (meaning
I could code them for just their work).

My method of achieving this was to create custom page controls for the areas
and then dynamically include them into the page using:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
// add the header...
Controls.AddAt(1, LoadControl(@"~\Common\ApplicationHeader.ascx"));
}

protected override void OnPreRender(EventArgs e)
{
// add the footer...
Controls.AddAt(Controls.Count-1,
LoadControl(@"~\Common\ApplicationFooter.ascx"));
base.OnPreRender (e);
}


The left navigation ascx control was also included from the header part.

The key to not interfering with the control hierarchy was to use this code
in the header:

<script language="javascript">document.write("<table width='100%'
cellspacing='0' cellpadding='0' border='0'><tr valign='top'><td
width='1%'>");</script>

<!-- Nav -->
<sierra:NavigationMenu id="Menu" runat="server" />

<script language="javascript">document.write("</td><td
valign='top'>");</script>

And use this code in the footer to close the table:

<script
language="javascript">document.write("</td></tr></table>");</script>


So, this code just wraps the entire form object in a table so that the
content of each page developed can be formatted appropriately. You could
substitute the table code above with your DIV tags to get the wrapping you
need. Hope this helps.

Fred

Tim Colton said:
Although the method you suggest is a workaround, I still do not understand
why the problem occurs. Simply inserting a panel control in the object
hierarchy of the page shouldn't break the functionality of individual
controls.
The purpose of the intermediate class is to add graphics and navigation
controls to every page in a web site. Since the content will vary from page
to page, I do not want to have to scan the object collection looking for
buttons so that I can "manually" add the onclick attribute.
Furthermore, the validation code can be triggered by controls other than
buttons. For example, you can have a textbox with autopostback which has an
associated regular expression validator. When someone types in the textbox,
and then hits the enter key, client side validation occurs before the
postback.
I just tried this scenario with and without my intermediate class. If the
web form inherits from the System.Web.UI.Page the validation occurs as
expected. When the web form inherits from my intermediate class, no
validation occurs. This situtation is really odd because the validation
code is tied to the Form object. In both cases the validation code is
properly set up. It just doesn't work in the second scenario (when
inheriting from the intermediate class).
In looking at the javascript in the browser source and in the
webUIValidation.js file, it looks like the code recursively walks through
the controls on the page. I wonder if this could be part of the problem.
Perhaps when the code encounters the "div" tag (which is what the panel
object gets rendered to) it exits the code early and the validation controls
do not get set up properly.
 
J

Jeffrey Tan[MSFT]

Hi Tim,

Does my reply make sense to you? Can you tell me why you need to change
the control tree at run-time?

Please feel free to post. Thanks

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
T

Tim Colton

Thanks for your suggestion Fred. I have been able to work around the problem by using Literal controls which insert the start and end "div" tags. It's a much more cumbersome method. Rather than a simple, clean while loop I have to use a total of twelve literal controls. The actual page has six panels; five have user controls for navigation elements and banners, one panel is the content panel which receives whatever content is on the web form.
 
T

Tim Colton

The reason I am changing the control hierarchy at run time is that this allows me to have a consistent navigation structure and graphical look on every page throughout the site. In the example I have shown in this thread I am adding one panel. The actual web application adds six panels: top graphic, global navigation, left navigation, content panel, page footer, and bottom navigation. The placement of the panels on the page is controlled by a CSS stylesheet. Each of the panels (with the exception of the content panel) hosts a user control. These user controls provide the consistent site wide navigation and graphics

For purposes of this thread discussion, I showed only one panel which is the content panel. This panel is where any controls added by the person designing the web form are moved by the intermedidate class. The advantage of this system is that the person working on an individual web form does not need to worry about any of the site-wide navigation or graphics. They just focus on adding the content for that form

Master templates are being added to the Whidbey release to provide this kind of capability. But considering Whidbey is still a year or more away, I need to implement this capability using the 1.1 framework.
 
F

Fred Hirschfeld

Then a question back to you would be is there some change I could make to
mine and use the Literal controls instead of the script without much work?

Fred

Tim Colton said:
Thanks for your suggestion Fred. I have been able to work around the
problem by using Literal controls which insert the start and end "div" tags.
It's a much more cumbersome method. Rather than a simple, clean while loop
I have to use a total of twelve literal controls. The actual page has six
panels; five have user controls for navigation elements and banners, one
panel is the content panel which receives whatever content is on the web
form.
 
J

Jeffrey Tan[MSFT]

Hi Tim,

Sorry for letting you wait for so long time. I have been sick leave for
these 2 days. Anyway, let's continue this thread.

Yes, from your description I see your concern. I think Fred's suggestion
should work for you.(I think you have checked it)

For your still problem about 6 panels, because the control tree problem
only occurs with validation, I think your other 5 panels should have no
validation problem, so you only need do special process for your content
panel.

Hope I did not misunderstand you.

Thank you for your patience and cooperation. If you have any questions or
concerns, please feel free to post it in the group. I am standing by to be
of assistance.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi Tim,

Does my reply make sense to you? Do you still have any concern on this
issue?

Please feel free to post. Thanks

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
G

Greg Ewing

Jeffrey, I'm confused as to how to make this work. I'm running in to
the same problem and what I think you are saying is that the problem
is the fact that I'm changing the control tree at runtime. The
function I'm using to do that is this one:

private void AddControlsFromDerivedPage(TableCell cell)
{
int count = this.Controls.Count;
for( int i = 0; i<count; ++i )
{
System.Web.UI.Control ctrl = this.Controls[0];
if (ctrl.ID == null || !ctrl.ID.Substring(0,
4).ToLower().Equals("base"))
{
//Trace.Write(ctrl.Parent.ToString());
cell.Controls.Add( ctrl );
this.Controls.Remove( ctrl );
}
}
}

This takes all of teh controls from the page that inherits my base
page and adds them to the right place on the page (the cell is passed
as an argument).

All of my controls end up in a table so I'm not sure that the table
possibility outlined earlier in this thread will work for me. Is
there any other work around or do you have any suggestions?

Greg
 
G

Greg Ewing

Jeffrey, I found a solution to my problem.

-- Quoted from an anonymous source --

Since there is a validators collection inside page, the remove(ctrl)
was also removing them from the validators collection, but the
form.controls.add doesn't added to the validators collection, so the
solution is:

private void AddControlsFromDerivedPage(HtmlForm form){
int count = this.Controls.Count;
for( int i = 0; i System.Web.UI.Control ctrl = this.Controls[0];
form.Controls.Add( ctrl );
if (!(ctrl is System.Web.UI.IValidator)){ this.Controls.Remove( ctrl
);
}
else
Page.Validators.Add((IValidator)ctrl);
}
}

Greg Ewing
C# MVP
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,480
Members
44,900
Latest member
Nell636132

Latest Threads

Top