[BUG]: Incredible bug on the webpartmanager control

Last post 05-17-2006 5:18 AM by Luis Abreu. 7 replies.

Sort Posts:

  • [BUG]: Incredible bug on the webpartmanager control

    05-16-2006, 8:02 AM
    • All-Star
      25,662 point All-Star
    • Luis Abreu
    • Member since 02-12-2005, 1:22 AM
    • Madeira [Portugal]
    • Posts 5,368
    • TrustedFriends-MVPs

    hello guys.

    this is INCREDIBLE!

    ok, let me start by explaining the scenario:
    1. page has 2 main areas: login and web zones
    2. initially, the login is visible and the divs are hidden
    3.  during the load event, the displaymode property of the scriptmanager is set to designdisplaymode (only if the current user is authenticated)
    4. the web parts controls (all of them) are inside an updatepanel

    one aditional note: the login is done using the authenticationservice and this causes a click over a hidden button which is placed inside the updatepanel so that the page is partially refreshed.

    ok, now the problem is that after loging in, i still wasn't able to drag-n-drop the webparts. if i refreshed the page, then everything was ok. so i started investigating and found the problem.

    the problem is that when the webpartmanager is in designmode, it injects a hidden div element on the page. unfortunatelly it does this ny using a real bad approach (this is just my opinion): it mixes it with the client script code and everything is injected with the registerXXX api. as a result, the partial postback receives this as a reply for an update:

    ..previous content removed

    <script type="text/javascript">
    <!--
    document.getElementById('aut').style.display = 'none';var __wpmExportWarning='This Web Part Page has been personalized. As a result, one or more Web Part properties may contain confidential information. Make sure the properties contain information that is safe for others to read. After exporting this Web Part, view properties in the Web Part description file (.WebPart) by using a text editor such as Microsoft Notepad.';var __wpmCloseProviderWarning='You are about to close this Web Part.  It is currently providing data to other Web Parts, and these connections will be deleted if this Web Part is closed.  To close this Web Part, click OK.  To keep this Web Part, click Cancel.';var __wpmDeleteWarning='You are about to permanently delete this Web Part.  Are you sure you want to do this?  To delete this Web Part, click OK.  To keep this Web Part, click Cancel.';// -->
    </script>


    <div id="manager___Drag" style="display:none; position:absolute; z-index: 32000; filter:alpha(opacity=75)"></div>
    <script type="text/javascript">

    __wpm = new WebPartManager();
    __wpm.overlayContainerElement = document.getElementById('manager___Drag');
    __wpm.personalizationScopeShared = false;

    var zoneElement;
    var zoneObject;

    ...more content follows

    this is just an excerpt...note the line in bold...this is placed outside the panelcontent element and due to this isn't inserted on the page. as a result, you just can't user web parts in this scenarios...if you don't believe me, then use reflector and see the contents of the method registerclientscript:

    protected virtual void RegisterClientScript()
    {
          this.Page.ClientScript.RegisterClientScriptResource(typeof(WebPartManager), "WebParts.js");
          bool flag1 = this.DisplayMode.AllowPageDesign;
          string text1 = string.Empty;
          string text2 = "null";
          if (flag1)
          {
                text1 = string.Format(CultureInfo.InvariantCulture, "\r\n<div id=\"{0}___Drag\" style=\"display:none; position:absolute; z-index: 32000; filter:alpha(opacity=75)\"></div>", new object[] { this.ClientID });
                text2 = "document.getElementById('" + this.ClientID + "___Drag')";
          }
          StringBuilder builder1 = new StringBuilder(0x400);
          foreach (WebPartZoneBase base1 in this._webPartZones)
          {
                string text3 = (base1.LayoutOrientation == Orientation.Vertical) ? "true" : "false";
                string text4 = "false";
                string text5 = "black";
                if (flag1 && base1.AllowLayoutChange)
                {
                      text4 = "true";
                      text5 = ColorTranslator.ToHtml(base1.DragHighlightColor);
                }
                builder1.AppendFormat("\r\nzoneElement = document.getElementById('{0}');\r\nif (zoneElement != null) {{\r\n    zoneObject = __wpm.AddZone(zoneElement, '{1}', {2}, {3}, '{4}');", new object[] { base1.ClientID, base1.UniqueID, text3, text4, text5 });
                WebPartCollection collection1 = this.GetWebPartsForZone(base1);
                foreach (WebPart part1 in collection1)
                {
                      string text6 = "null";
                      string text7 = "false";
                      if (flag1)
                      {
                            text6 = "document.getElementById('" + part1.TitleBarID + "')";
                            if (part1.AllowZoneChange)
                            {
                                  text7 = "true";
                            }
                      }
                      builder1.AppendFormat("\r\n    zoneObject.AddWebPart(document.getElementById('{0}'), {1}, {2});", part1.WholePartID, text6, text7);
                }
                builder1.Append("\r\n}");
          }
          string text8 = string.Format(CultureInfo.InvariantCulture, "\r\n{0}\r\n<script type=\"text/javascript\">\r\n\r\n__wpm = new WebPartManager();\r\n__wpm.overlayContainerElement = {1};\r\n__wpm.personalizationScopeShared = {2};\r\n\r\nvar zoneElement;\r\nvar zoneObject;\r\n{3}\r\n</script>\r\n", new object[] { text1, text2, (this.Personalization.Scope == PersonalizationScope.Shared) ? "true" : "false", builder1.ToString() });
          this.Page.ClientScript.RegisterStartupScript(typeof(WebPartManager), string.Empty, text8);
    }

    i think i can say that this is really some "exotic" code. so, when will you fix this?

    thanks.

    --
    Regards,
    Luis Abreu
    email: labreu_at_gmail.com
    EN blog:http://msmvps.com/blogs/luisabreu
  • Re: [BUG]: Incredible bug on the webpartmanager control

    05-16-2006, 6:00 PM
    • All-Star
      25,662 point All-Star
    • Luis Abreu
    • Member since 02-12-2005, 1:22 AM
    • Madeira [Portugal]
    • Posts 5,368
    • TrustedFriends-MVPs
    just putting it back on top again...
    --
    Regards,
    Luis Abreu
    email: labreu_at_gmail.com
    EN blog:http://msmvps.com/blogs/luisabreu
  • Re: [BUG]: Incredible bug on the webpartmanager control

    05-16-2006, 6:23 PM
    • Participant
      828 point Participant
    • aosipov
    • Member since 04-07-2006, 1:22 PM
    • New York, NY
    • Posts 177

    Luis -

    I had similar problems with using ASP.NET WebParts and Atlas.  Basically what Atlas is doing is overwriting ASP.NET code and puts a much bigger limitation on anything you can do.  I had spent about two weeks investigating using Atlas with WebParts and came to the conclusion that Atlas is simply "hacking" WebParts.  I had eventually decided to refrain from using WebParts as it placed too many limitations on my design (no dynamic loading of web parts was a big limitation for me).  I had spent some times experimenting with adding custom chromes, paging support to web parts and while it was all possible to do (through my own hacks and overriding ASP.NET rendering) I eventually was at the point where I had my own classes to generate web part chromes, using my own verb classes, my own personalization provider and some client side scripts.  At this point I had thought about why I am using this framework (i.e. what was left of it) and decided to stop this route and go for my own solution.  I have been able to write the entire framework w/ dynamic loading, web part previews, catalog, data binding, a runtime engine for my own web parts (I call them web objects) using Atlas and it is working great.  Best part is I am not limited by the WebParts framework nor do I have to deal with scattered imperative code but can work with Atlas objects - soo much easier!

    In my opinon I don't think Atlas will be able to do much for WebParts in any useful way until both ASP.NET 2 and Atlas converge in v3, the current state is simply craziness.  I hope ASP.NET client side scripts in ASP.NET 3 will use Atlas libraries and then it will be a real Atlas approach rather than various hacks. 

    Good luck.  Just my 2 cents.

    AO

    Regards,
    Alex Osipov
  • Re: [BUG]: Incredible bug on the webpartmanager control

    05-16-2006, 6:26 PM
    • All-Star
      25,662 point All-Star
    • Luis Abreu
    • Member since 02-12-2005, 1:22 AM
    • Madeira [Portugal]
    • Posts 5,368
    • TrustedFriends-MVPs

    hello.

    yep, there are still some tough edges...however, in this case, it really isn't atlas fault... the webpartmanager is the one that should be blamed (ie, the guy that wrote the code for introducing the html and script on the client part). man, where did that guy  got the idea of mixing html and script and then using the registerXXX api to introduce everything on the page????

    --
    Regards,
    Luis Abreu
    email: labreu_at_gmail.com
    EN blog:http://msmvps.com/blogs/luisabreu
  • Re: [BUG]: Incredible bug on the webpartmanager control

    05-16-2006, 6:36 PM
    • Participant
      828 point Participant
    • aosipov
    • Member since 04-07-2006, 1:22 PM
    • New York, NY
    • Posts 177

    I can do you one better.... where did he get the idea to hard code verb icon width and height to 9 (or some other pixel value, I forget).... on the client side....WHYYYYY!!!!

    WebParts client side scripts drove me a little nuts for a few days, navigating around all the web resources and looking up __ internal objects it uses and then figuring out what Atlas is doing but eventually I got it down.   I really think WebParts was introduced more for compatibility with SharePoint so you can create your own Web Part objects rather than use the standard ASP.NET WebPartManager and WebPartZone.  However, they couldn't release a WebPart class with .NET without a manager to go with it...

    Regards,
    Alex Osipov
  • Re: [BUG]: Incredible bug on the webpartmanager control

    05-16-2006, 6:44 PM
    • All-Star
      25,662 point All-Star
    • Luis Abreu
    • Member since 02-12-2005, 1:22 AM
    • Madeira [Portugal]
    • Posts 5,368
    • TrustedFriends-MVPs

    hello again...

    nice question :)

    well, i must say that this one (mixing html and javascript) is still my favourite one :D

    --
    Regards,
    Luis Abreu
    email: labreu_at_gmail.com
    EN blog:http://msmvps.com/blogs/luisabreu
  • Re: [BUG]: Incredible bug on the webpartmanager control

    05-16-2006, 7:43 PM
    • Contributor
      4,557 point Contributor
    • mharder
    • Member since 11-22-2002, 12:03 PM
    • Redmond, WA
    • Posts 917
    • Moderator
    I'm the developer for both ASP.NET 2.0 WebParts and Atlas WebParts.  Let me try to answer your questions.

    1. It sounds like some combination of WebParts + UpdatePanel is not working for you.  Are you using the ASP.NET 2.0 WebParts controls, or the Atlas WebParts controls.  I know the Atlas WebParts controls are compatible with UpdatePanel.  If the ASP.NET 2.0 WebParts controls do not work with UpdatePanel, then the workaround is to use the Atlas WebParts controls instead.

    2. You have a good point about using RegisterClientScript() to insert the <div> into the page.  This is an improper use of RegisterClientScript().  However, this hasn't caused any issues outside of the UpdatePanel scenario, so it wasn't caught before Whidbey shipped.  Note that lots of third-party controls have issues like this with UpdatePanel as well.  It's extremely hard for UpdatePanel to guarantee that it will work with any existing ASP.NET control, including those that misused APIs like RegisterClientScript().

    Let me know if you have any other questions, and I'll be happy to work with you.

    -Mike
    http://blogs.msdn.com/mharder

    This posting is provided "AS IS" with no warranties, and confers no rights.
  • Re: [BUG]: Incredible bug on the webpartmanager control

    05-17-2006, 5:18 AM
    • All-Star
      25,662 point All-Star
    • Luis Abreu
    • Member since 02-12-2005, 1:22 AM
    • Madeira [Portugal]
    • Posts 5,368
    • TrustedFriends-MVPs

    Hello Mike.

    glad to get your attention.

    1.

    yes, they are....but not in all scenarios. here's an example:

    suppose you have a page with 2 areas: one let's you login and the 2nd let's you work with webparts. only one of them is visible, since i want to let users change the web parts as they like. here's an example of a quick page i've built (never mind the code...yes, it could be better, but i also think that you 'll be able to reproduce the bug there):

    <%@ Page Language="C#" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <script runat="server">
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            if (this.User.Identity.IsAuthenticated)
            {
                manager.DisplayMode = WebPartManager.DesignDisplayMode;
                this.ClientScript.RegisterStartupScript(this.GetType(),
                    "page",
                    "document.getElementById('aut').style.display = 'none';",
                    true);
            }
            else
            {
                this.ClientScript.RegisterStartupScript(this.GetType(),
                    "page",
                    "document.getElementById('zone1').style.display = 'none';document.getElementById('zone2').style.display = 'none';",
                    true);
            }
           
        }
    </script>

    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Untitled Page</title>
        <style type="text/css">
           
           
            #zone1
            {
                position:relative;
                float: left;
                width: 350px;
                height: 500px;
                border: dashed 1px red;
            }
           
            #zone2
            {
                position:relative;
                float: right;
                width: 350px;
                height: 500px;
                border: dashed 1px red;
            }     
        </style>
        <script type="text/javascript">
            function login()
            {
                 Sys.Services.AuthenticationService.login(
                                        $("username").value,
                                        $("pass").value,
                                        false,
                                        callback );
            }
           
            function callback( res )
            {
                if( res )
                {
                   $("aut").style.display = "none";
                   $("zone1").style.display = "";
                   $("zone2").style.display = "";
                   $("refresher").click();
                }
            }
        </script>
    </head>
    <body>
        <form id="form1" runat="server">
           
            <atlas:ScriptManager runat="server" EnablePartialRendering="true" />
           
            <div id="aut">
                <span>Nome de utilizador:</span>
                <input type="text" id="username" />
                <br />
                <span>Palavra-chave:</span>
                <input type="password" id="pass" />
                <br />
                <input type="button" value="Login" onclick="login()" />
            </div>
           
            <atlas:UpdatePanel runat="server" ID="panel">
                <ContentTemplate>
                    <asp:WebPartManager runat="server" ID="manager"  />
                   
                   
                    <div id="zone1" runat="server">
                        <asp:WebPartZone ID="WebPartZone2" runat="server" BorderColor="#CCCCCC" Font-Names="Verdana"
                            Padding="6">
                            <PartChromeStyle BackColor="#E3EAEB" BorderColor="#C5BBAF" Font-Names="Verdana" ForeColor="#333333" />
                            <MenuLabelHoverStyle ForeColor="Yellow" />
                            <EmptyZoneTextStyle Font-Size="0.8em" />
                            <MenuLabelStyle ForeColor="#333333" />
                            <MenuVerbHoverStyle BackColor="#E3EAEB" BorderColor="#CCCCCC" BorderStyle="Solid"
                                BorderWidth="1px" ForeColor="#333333" />
                            <HeaderStyle Font-Size="0.7em" ForeColor="#CCCCCC" HorizontalAlign="Center" />
                            <ZoneTemplate>
                                <asp:Calendar ID="Calendar1" runat="server"></asp:Calendar>
                            </ZoneTemplate>
                            <MenuVerbStyle BorderColor="#1C5E55" BorderStyle="Solid" BorderWidth="1px" ForeColor="White" />
                            <PartStyle Font-Size="0.8em" ForeColor="#333333" />
                            <TitleBarVerbStyle Font-Size="0.6em" Font-Underline="False" ForeColor="White" />
                            <MenuPopupStyle BackColor="#1C5E55" BorderColor="#CCCCCC" BorderWidth="1px" Font-Names="Verdana"
                                Font-Size="0.6em" />
                            <PartTitleStyle BackColor="#1C5E55" Font-Bold="True" Font-Size="0.8em" ForeColor="White" />
                        </asp:WebPartZone>
                   
                    </div>
                   
                    <div id="zone2"  runat="server">
                        <asp:WebPartZone ID="WebPartZone1" runat="server" BorderColor="#CCCCCC" Font-Names="Verdana"
                            Padding="6">
                            <PartChromeStyle BackColor="#E3EAEB" BorderColor="#C5BBAF" Font-Names="Verdana" ForeColor="#333333" />
                            <MenuLabelHoverStyle ForeColor="Yellow" />
                            <EmptyZoneTextStyle Font-Size="0.8em" />
                            <MenuLabelStyle ForeColor="#333333" />
                            <MenuVerbHoverStyle BackColor="#E3EAEB" BorderColor="#CCCCCC" BorderStyle="Solid"
                                BorderWidth="1px" ForeColor="#333333" />
                            <HeaderStyle Font-Size="0.7em" ForeColor="#CCCCCC" HorizontalAlign="Center" />
                            <ZoneTemplate>
                                <asp:Calendar ID="Calendar2" runat="server"></asp:Calendar>
                            </ZoneTemplate>
                            <MenuVerbStyle BorderColor="#1C5E55" BorderStyle="Solid" BorderWidth="1px" ForeColor="White" />
                            <PartStyle Font-Size="0.8em" ForeColor="#333333" />
                            <TitleBarVerbStyle Font-Size="0.6em" Font-Underline="False" ForeColor="White" />
                            <MenuPopupStyle BackColor="#1C5E55" BorderColor="#CCCCCC" BorderWidth="1px" Font-Names="Verdana"
                                Font-Size="0.6em" />
                            <PartTitleStyle BackColor="#1C5E55" Font-Bold="True" Font-Size="0.8em" ForeColor="White" />
                        </asp:WebPartZone>       
                    </div>
                    <asp:Button ID="refresher" runat="server" style="display: none" />
                </ContentTemplate>
            </atlas:UpdatePanel>
        </form>
    </body>
    </html>

    so, the problem happens after performing the login. since i don't run a complete postback page, the div used to make the drag-n-drop will not be added to the page (because it was injected with the script, and not added as a child control) and due to that, you won't be able to performa drag-n-drop operation on the web parts.

    replacing the components with the one introduced by atlas results in assertions on the client side related with duplicate id (on all these components). i'm guessing that the controls are being re-added with xml-script during the partial postbacks...as i said, i didn't had any time to check it by inspecting the code, but this is what it looks like.

    thanks again.

    --
    Regards,
    Luis Abreu
    email: labreu_at_gmail.com
    EN blog:http://msmvps.com/blogs/luisabreu
Page 1 of 1 (8 items)