Blog Home  Home RSS 2.0 Atom 1.0 CDF  
The Moon Upstairs - Monday, March 26, 2007
and other issues programming .Net
 
 Monday, March 26, 2007

A recent project I've been working on is a knowledge base with dynamic data structures.  As such, all of the controls placed on the update page are dynamically created at runtime. 

There is a drop down list for country and state, with the country list causing a post back to fill the state list.  We needed the page to scroll back to the country list after postback to relieve the user of having to scroll down two pages. 

It didn't take much research to find the Page directive MaintainScrollPositionOnPostback="true".  While this did get the page to scroll back to the drop down list, it also caused the page to scroll back to the submit button when there was a validation error (all done on the server side).  Hey, no problem, I'll just set that directive programatically only when the post back is caused by that drop down list.

I found a nice article by Peter Bromberg on a way to determine the control that causes a post back at http://www.eggheadcafe.com/articles/20050609.asp.  I got null exceptions when trying to return the control, so I changed the code slightly to just return a string that describes the type of control.

But more null exceptions awaited me when I tried to set the scroll back directive from the drop down list call back function.  Apparently this was also related to the dynamic nature of the page.  I decided to abandon the page directive and to wade into Javascript.

An article at ASP.Net magazine by Brad McCabe, http://www.aspnetpro.com/NewsletterArticle/2003/09/asp200309bm_l/asp200309bm_l.asp got  me started in the right direction.  The functions presented would save the scroll position in a hidden field, and that field would later be used to set the scroll position.  I converted the functions to C# and implemented them in my Page.OnInit function.  After getting all the Javascript errors resolved (always a chore for me), the page refused to scroll on post back.

Using a neat Javascript trace utility from http://www.interlogy.com/~cigdem/trace/ I was able to determine that "theBody.scrollTop", which I translated as "document.body.scrollTop", was not returning anything.  So I was saving nothing to the hidden control.

Looking further I found a set of Javascript functions by "Tigra" at http://www.softcomplex.com/docs/get_window_size_and_scrollbar_position.html that would find the x or y scroll postion, and the height and width of the window.  The article also has a great cross reference table for different browsers and the window/scroll functions supported by each.

I only needed the y scroll function, and used a call to it to replace the document.page.scrollTop property.  Now Tracer was confirming that I was saving the correct scroll position, but alas the page did not scroll back.  After a little more debugging I determined the page would never scroll by setting the document.body.scrollTop in this situation since this is just a property you are setting.  Something else would have to read that value to set the scroll.  I had no idea what that might be since Javascript is not my strong point. 

But there is a scroll function, and by calling scroll(0, [saved y value]) I was able to finally get the page to scroll back only to the drop down list.

The post back control function, in App_Data/Global.asax.cs:

    public static string GetPostBackControlType(System.Web.UI.Page page)
    {
        string objectType = string.Empty;
        Control control = null;
        string ctrlname = page.Request.Params["__EVENTTARGET"];

        if (ctrlname != null && ctrlname != String.Empty)
        {
            control = page.FindControl(ctrlname);
        }
          // if __EVENTTARGET is null, the control is a button type and we need to
          // iterate over the form collection to find it
        else
        {
            string ctrlStr=String.Empty;
            Control c=null;
           
            foreach (string ctl in page.Request.Form)
            {
                // handle ImageButton controls ...
                if (ctl.EndsWith(".x") || ctl.EndsWith(".y"))
                {
                    ctrlStr = ctl.Substring(0,ctl.Length-2);
                    c= page.FindControl(ctrlStr);
                }
                else
                {
                    c = page.FindControl(ctl);
                }
                if (c is System.Web.UI.WebControls.Button ||
                   c is System.Web.UI.WebControls.ImageButton)
                {
                    control = c;
                    break;
                }
            }
        }

        if (control != null)
        {
            objectType = control.GetType().ToString();
        }

        return objectType;

    } 

The Javascript placed in the body of the aspx page:

    <script type="text/javascript" language="javascript">
        
       function SaveScrollLocation () {
            //trace('Scroll Top = ' + f_scrollTop());
            window.document.forms[0].__SCROLLLOC.value = f_scrollTop();
        }
        window.document.body.onscroll=SaveScrollLocation;

       function f_scrollTop() {
            return f_filterResults (
                window.pageYOffset ? window.pageYOffset : 0,
                document.documentElement ? document.documentElement.scrollTop : 0,
                document.body ? document.body.scrollTop : 0);
        }

       function f_filterResults(n_win, n_docel, n_body) {
            var n_result = n_win ? n_win : 0;
            if (n_docel && (!n_result || (n_result > n_docel)))
                n_result = n_docel;
            return n_body && (!n_result || (n_result > n_body)) ? n_body : n_result;
        }
    </script>

The C# snippit placed in the Page OnInit function:

            // hidden field to store scroll location
            Page.ClientScript.RegisterHiddenField("__SCROLLLOC", "0");

            if (Page.IsPostBack)
            {
                string ctrlType = Global.GetPostBackControlType(this);

                if (ctrlType.Contains("DropDownList"))
                {
                    // Keep scroll at the country drop down list
                    SetScrollLocation();
                }
            }

The C# function to Set the Scroll Location:

    private void SetScrollLocation()
    {
        StringBuilder jsSB = new StringBuilder();

        jsSB.Append("<script language='javascript'>");
        jsSB.Append("function SetScrollLocation () {");
        jsSB.Append("  scroll(0," + Request["__SCROLLLOC"] + ");");
        jsSB.Append("}");
        jsSB.Append("window.document.body.onload=SetScrollLocation;");
        jsSB.Append("</script>");
       
        Page.ClientScript.RegisterClientScriptBlock(Page.GetType(), "setScroll", jsSB.ToString());

    }

While this implementation only acts on the DropDownList, you could easily extend it to different controls or different dropdowns by returning the ID of the control causing the postback.

Monday, March 26, 2007 11:57:39 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]    |  |   |  Trackback
 Monday, March 05, 2007

I recently had all my entries disappear from this blog.  After reading about the problem at dasblog.us I extended the session timeout on the site.  It looks to me like the session expired during a lengthy editing session, and left the system in an unstable state.  I had to upload a new version of web.config to get my content to display once more. 

This entry was created using Widows Live Writer, which writes directly to the site and will avoid any session timeouts. 

Monday, March 05, 2007 4:02:54 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]    |   |  Trackback

I was tasked with developing a web service for our development team that would mimick the operation of a client web service that has access limited by IP address. This target service was developed with WSE 2.0.  The encryption used in WSE 2.0 is different from that in 3.0.  Allthough some posts I read said you could change the encryption mode, I decided it would be less risky to adapt WSE 2.0 to ASP.NET 3.0. 

There are lots of sample programs for using WSE 3.0 in ASP.Net 2.0, but none using WSE 2.0. Here are a couple of things that I had to change in the Web.Config given in the sample projects that come with the WSE install:


<
security>
<
x509 storeLocation="LocalMachine" allowTestRoot="true" allowRevocationUrlRetrieval="false" verifyTrust="true"/>
<!--
Replaced UsernameSignCodeService with App_Code for using WSE 2.0 in VS2005!!!! -->
<
securityTokenManager type="EcsMockWebService.CustomUsernameTokenManager, App_Code" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" qname="wsse:UsernameToken" />
</
security>


<
webServices>
<
soapExtensionTypes>
<!--
group="0" removed from the end of the following line to use WSE 2.0 in ASP.Net 2.0 -->
<
add type="Microsoft.Web.Services2.WebServicesExtension, Microsoft.Web.Services2, Version=2.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" priority="1"/>
</
soapExtensionTypes>
</
webServices>

Monday, March 05, 2007 2:02:12 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]    |  |   |  Trackback
 Monday, January 29, 2007
Validating alternate date formats in ASP.Net
Monday, January 29, 2007 11:53:54 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]    |  Trackback
 Monday, January 15, 2007
Getting ASP.Net to play pretty with CSS.
Monday, January 15, 2007 11:25:30 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]    |  Trackback
 Tuesday, November 28, 2006
New Web Hosting Service
Tuesday, November 28, 2006 11:27:15 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]    |  Trackback
Copyright © 2008 Fred Peters. All rights reserved.
DasBlog 'Portal' theme by Johnny Hughes.