Workaround: Empty Design View for User Controls

Workaround: Empty Design View for User Controls

  • Comments 13

I've noticed quite a few people run into the issue "Why is design mode empty for my web user control (ASCX)?".  It's not obvious what might be causing this bug, so I thought I'd offer an explanation and a couple workarounds.

Problem

You have a user control that has a "link" tag to an external style sheet or a "style" tag with local styles at the top of the page.  Immediately below the style, you have a web control (such as a Wizard control) that contains the bulk of the content.  You attempt to edit this user control in design view and all you see is an empty page.  Here's a trivial example:

Blank design view screen

Explanation

Design view was originally created to handle full HTML pages where the "body" and "head" tags were present.  If these two tags are missing, and something else comes along that normally belongs in the "head" (a "style", "link", or even "meta"), the parser will create a virtual "head" and "body" to enclose that element and any other elements following it until it sees something that normally does not belong in the head (such as a "form").  Rationalizing a parse tree is not an unusual practice and makes the implementation of other parts of the design view easier.

These days we use the same parser to handle ASCX files, which routinely lack a head and a body.  However, the artifact behavior of the parser still exists.  Thus it will consume the "style" tag and the following web control since it does not recognize the web control as something that clearly belongs outside of the head.  From the point of view of Visual Studio, your web control is inside the head tag (and nothing is in the body).  Thus, you see nothing rendered on screen.

We plan on addressing this issue, however parser changes are non-trivial so you'll have to excuse the delay.

Workarounds

Luckily there are a few workarounds that can remedy the situation.  The first is to move the "style" or "link" tag to the bottom of the ASCX file.  Your CSS will behave the same even after the reordering.  As long as you don't mind the order being reversed, this is a good solution.  An alternate workaround is to write the content (excluding the "style" or "link" tags) in a "div" or a "span".  Both of these tags are neutral to the appearance of your control so you're not sacrificing the design of your control.  The "div" or "span" signal the parser to exit the "head" tag thus avoiding the bug.

I hope the insight allows folks to steer clear of the issue and the workarounds unblock your work!

Jeff King
Program Manager
Visual Studio Web Tools

Leave a Comment
  • Please add 6 and 8 and type the answer here:
  • Post
  • PingBack from http://www.basketballs-sports.info/basketball-chat/?p=1160

  • Thanks for the heads up, Jeff.

  • Esto no paso ayer.. paso hace ya varios días atrás... estaba en la oficina trabajando ( aunque muchos

  • Esto no paso ayer.. paso hace ya varios días atrás... estaba en la oficina trabajando ( aunque muchos

  • Enclosing the content in div tags didn't solve the problem and moving the style link to the bottom of the ascx allowed the content to display, but it was not rendered with the styles

  • Pamela, can you provide a sample ASCX page that reproduces the problem? Either of those workaround should've normally worked. If I try this out myself I might be able to help.

    You can email the page to:

    p e t e r s p a "at" microsoft "dot" com

    Just remove all the extra spaces from the email name.

  • Adding a DIV element did not work for me. If I add text content to the control then the text displays in the hosting page without problems. I can put the text before and after the control's content, and the text displays normally. I can surround the control's content with a DIV element, even put text before and after the start and end tags of the DIV, and only see the text and an outline of the control's content, but nothing else.

    While writing up this comment, I decided to remove the asp:Panel control and now the control's content displays as expected. I can reproduce the problem.

  • I have tried the <span>, <div> and bottom link placement. In VS2008 my control always renders, although It will not recognize the style sheet links. I always get 'The class or CssClass value is not defined.' In any case the link is rendered in the body, so will not validate as XHTM 1 strict. Here is my workaround so far: Maybe someone has something better

    'In user control

    Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) _

       Handles Me.PreRender

       CStyleSheet.MoveLinksToHeader(Me)

     End Sub

    Public Class CStyleSheet

     'call from the user control's prerender e.g. CStyleSheet.MoveLinksToHeader(Me)

     'Linked stylesheets can be placed at the bottom of a user control's markup source.

     'However, if the user control is placed in the Html body, then the final output will not be Xhtml compliant,

     'since any link elements are not allowed in the body.

     'This method moves these link elements to the header, without duplicating them.

     'The link elements must have a unique id for the page, but common the the specific stylesheet and the runat="server" attribute.

     Public Shared Sub MoveLinksToHeader( _

       ByVal voUserControl As System.Web.UI.UserControl)

       Dim tAttribute As String

       Dim tAttributeKey As String

       Dim tAttributeValue As String

       Dim oControl As System.Web.UI.Control

       Dim oHtmlLink As HtmlControls.HtmlLink

       Dim oHtmlGenericControl As System.Web.UI.HtmlControls.HtmlGenericControl

       Dim oHtmlGenericControls As System.Collections.Generic.List(Of HtmlControls.HtmlGenericControl)

       With voUserControl

         oHtmlGenericControls = New System.Collections.Generic.List(Of HtmlControls.HtmlGenericControl)

         For Each oControl In .Controls

           oHtmlGenericControl = TryCast(oControl, System.Web.UI.HtmlControls.HtmlGenericControl)

           'if a potential link control is found, then

           If oHtmlGenericControl IsNot Nothing Then

             tAttribute = oHtmlGenericControl.Attributes.Item("rel")

             'if the control has a rel attribute key, then

             If Not System.String.IsNullOrEmpty(tAttribute) Then

               'if the control has a rel attribute with a stylesheet value, then

               If System.String.Compare(tAttribute, "stylesheet", True) = 0I Then

                 tAttribute = oHtmlGenericControl.Attributes.Item("href")

                 'if the control has a href, then

                 If Not System.String.IsNullOrEmpty(tAttribute) Then

                   'if the control has not been added the the page header, then

                   If .Page.Header.FindControl(oHtmlGenericControl.ID) Is Nothing Then

                     'create a new html link control, since the html generic control won't cast

                     oHtmlLink = New HtmlControls.HtmlLink

                     'copy the generic link control's id to the new html link control's id

                     oHtmlLink.ID = oHtmlGenericControl.ID

                     'copy the generic link control's attributes to the new html link control

                     For Each tAttributeKey In oHtmlGenericControl.Attributes.Keys

                       tAttributeValue = oHtmlGenericControl.Attributes.Item(tAttributeKey)

                       oHtmlLink.Attributes.Add(tAttributeKey, tAttributeValue)

                     Next tAttributeKey

                     'add the new html link control to the header

                     .Page.Header.Controls.Add(oHtmlLink)

                   End If

                   'add the generic link control to a collection for post loop removal

                   oHtmlGenericControls.Add(oHtmlGenericControl)

                 End If

               End If

             End If

           End If

         Next

         'remove every generic link control from the user control, which have been copied to the header

         For Each oHtmlGenericControl In oHtmlGenericControls

           .Controls.Remove(oHtmlGenericControl)

         Next

       End With

     End Sub

  • Philip, dynamic moving of elements in server code won't work in the designer since user code is not running at design time. You need to physically (manually) move <link> element down.

  • Anthony,

    Once you add the DIV, you probably need to reopen the file, or just choose View|Refresh. This will force the previously hidden control to update its design time HTML and it'll show up in design view (well, that worked when I tried it).

  • WebDevTools, I have the link at the bottom of the user control layout. I still get 'The class or CssClass value is not defined.' in VS2008. The above code is so at least the rendered page is XHTML 1.0 strict. I wrote that so I don't have to manually add the style sheet links to the page where the control is used. I think they idea of a user control is better preserved this way, since its dependancies are encapsulated in the control. Thanks Philip

  • I can confirm that this works, you just need to follow WebDevTools' instructions to either close & reopen, or refresh the designer once you've altered the code.

    I have to say though, this is a pretty glaring bug in Visual Studio, and definitely something that internal testing should have picked up.

  • Hello everybody,

    I have been struggling with this very problem. I have tried everything above and my ASCX file still does not render in the designer. I am at a loss. I have done a install/repair, installed the VS 2008 hotfix but still nothing in the designer. Here is my ascx with the asp:panel replaced with a div based on reading above. This is a Dotnetnuke ASCX file. Can somebody provide help on getting this type of control to render in the VS 2008 designer?

    <%@ Control language="vb" Inherits="IPS.Dnn.Tasklist.AddTask" AutoEventWireup="false" Explicit="True" Codebehind="AddTask.ascx.vb" %>

    <%@ Register TagPrefix="dnn" TagName="Label" Src="~/controls/LabelControl.ascx" %>

    <div>

       <table id="tblAddTask" summary="Edit Table" class="tblAddTask">

           <tr valign="top">

               <td>&nbsp;</td>

               <td class="SubHead"><%= Localization.GetString("Priority.Text", LocalResourceFile) %></td>

               <td class="SubHead"><%= Localization.GetString("Reminder.Text", LocalResourceFile) %></td>

           </tr>

       <tr valign="top">

       <td class="SubHead"><dnn:label id="lblTask" runat="server" controlname="lblTask" resourcekey="lblTask" suffix=":" /></td>

       <td>

       <asp:DropDownList id="ddlTaskPriority" runat="server"></asp:DropDownList>

    </td>

    <td>

                   <asp:TextBox ID="txtTaskTitle" runat="server" class="txtTaskTitle" /><asp:RequiredFieldValidator ID="rfvTaskTitle" ControlToValidate="txtTaskTitle" CssClass="NormalRed" Display="Dynamic" resourcekey="rfvTaskTitle" Runat="server" />

       </td>

       </tr>

       <tr>

           <td colspan="3" class="center">

               <asp:linkbutton cssclass="CommandButton" id="btnAddTask" OnClick="AddTask_Click" runat="server" />&nbsp;

                   <asp:linkbutton cssclass="CommandButton" id="btnCancel" OnClick="Cancel_Click" runat="server" causesvalidation="False" />

               </td>

           </tr>

       </table>

    </div>

    Thanks in advance for your help!

    Regards, Todd.

Page 1 of 1 (13 items)