65.9K
CodeProject is changing. Read more.
Home

Convert a Usercontrol to a WebControl

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.08/5 (6 votes)

Aug 11, 2004

viewsIcon

72256

downloadIcon

614

You've created a beautiful usercontrol with HTML layout but you want to use it as a Server Control. This macro generates the instantiation and render code for you.

Introduction

Ever written a nice usercontrol and wanted to migrate it to a webcontrol? Then you'll know you have to write a lot of render and initialization stuff yourself. With this macro, some of it is generated out of the .ascx file you created.

For instance, if you have this code:

Ascx Code

Then this macro will output the following lines to the output window:

Resulting output

Then all you have to do is copy the code to the codebehind file, change the inherit, and presto, a webcontrol.

The macro:

Sub GenerateWebcontrolCode()
    Dim str As String = ""
    Dim createCC As String = ""
    Dim renderCC As String = ""
    Dim attribsCC As String = ""
    Dim selection As TextSelection = DTE.ActiveDocument.Selection()
    selection.SelectAll()
    Dim theText As String = selection.Text

    'all <asp:Label like tags and id's

    Dim r As New Regex("\<(?<tag>\w*):(?<type>\w*)" & _
      "(.\n?)*?id=\""?(?<id>\w*)\""?(.\n?)*?>", RegexOptions.IgnoreCase)
    Dim matches As MatchCollection = r.Matches(theText)
    Dim m As Match

    'set the startindex to position after the last <%@ register tag!!
    Dim startindex As Integer = 0
    Dim matchRegistertags As Match = Regex.Match(theText, _
                     "<%@.*?>", RegexOptions.RightToLeft)
    startindex = matchRegistertags.Index + matchRegistertags.Length
    If (startindex < 0) Then
        startindex = 0
    End If

    For Each m In matches
        'only start again after endtag (templated controls will not work!!)
        If m.Index > startindex Then

            Dim tp As String = m.Groups("type").Value
            Dim id As String = m.Groups("id").Value
            Dim tag As String = m.Groups("tag").Value

            'the stuff for the render override
            'Get the html in before the control 
            'and write this to the HTMLwriter
            Dim htmlstr As String = _
              theText.Substring(startindex, m.Index - startindex)
            htmlstr = htmlstr.Replace("""", """""")
            renderCC += "writer.Write(@""" + htmlstr + """);" + vbCrLf
            renderCC += id + ".RenderControl(writer);" + vbCrLf

            'Set the index to the position of the endtag (if available, 
            'otherwise control is closed with />
            startindex = m.Index + m.Length
            Dim endtag As String = "</" + tag + ":" + tp + ">"
            Dim inext2 As Integer = theText.IndexOf(endtag, startindex)
            If inext2 <> -1 Then
                startindex = inext2 + endtag.Length
            End If

            ' the stuff for the init procedures make sure you add this to 
            createCC += id + " = new " + tp + "();" + vbCrLf

            'Add attributes to the object.
            'Only attibutes assigned within the first tag no 
            'templated controls or default properties are set
            Dim r2 As New Regex("(?<prop>\w*)=\""?(?<value>\w*)\""?", _
                                                RegexOptions.IgnoreCase)
            Dim ms2 As MatchCollection = r2.Matches(m.Value)
            Dim m2 As Match
            For Each m2 In ms2
                Dim prop As String = m2.Groups("prop").Value
                Dim val As String = m2.Groups("value").Value
                If prop.ToLower() <> "runat" Then
                    createCC += id + "." + prop + " = """ + val + """;" + vbCrLf
                End If
            Next

            'add the control to the control collection
            createCC += "this.Controls.Add(" + id + ");" + vbCrLf + vbCrLf
        End If

    Next

    'render the final html after the last control
    Dim htmlstr2 As String = theText.Substring(startindex, _
                                   theText.Length - startindex)
    htmlstr2.Replace("""", """""")
    renderCC += "writer.Write(@""" + htmlstr2 + """);" + vbCrLf
    'now show the text om the output window
    Dim win As Window = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput)
    Dim OWp As OutputWindowPane = win.Object.OutputWindowPanes.Item(1)
    OWp.Clear()
    OWp.Activate()
    OWp.OutputString("-----------------" + vbCrLf)
    OWp.OutputString("Add this to the Init procedure" & _ 
                          " (before any events are assigned)" + vbCrLf)
    OWp.OutputString("TODO check type casing and property types," & _
                       " dynamically load templated elements" + vbCrLf)
    OWp.OutputString("-----------------" + vbCrLf)
    OWp.OutputString(createCC)
    OWp.OutputString("-----------------" + vbCrLf)
    OWp.OutputString("Add this to the render function" + vbCrLf)
    OWp.OutputString("-----------------" + vbCrLf)
    OWp.OutputString(renderCC)
    OWp.TextDocument.Selection.GotoLine(OWp.TextDocument.EndPoint().Line())
    DTE.ExecuteCommand("View.Output")
End Sub

Just copy paste the code into the .ascx.cs file and inherit from WebControl instead of UserControl. (Or if you want, create a new class file with both the code.)

Unfortunately, you'll have to check the casing of the types because if there is <asp:button in the ascx file, then the type will be button (lowercase), also check the type of the parameters assigned. (String type is assumed, see Button1.BorderWidth = "4px"; this should be just 4 of course.)

Well, good luck and hope this saves some typing.

Greetings Rooc.