James's profileJames's spacePhotosBlogLists Tools Help

James

Occupation
Location

James's space

October 26

Windows Live Local Listing Center

Have a business?  Add or edit your business listing with Windows Live Local Listing Center.  The recently launched Local Listing Center allows you to assign categories, photos and other information for display within Live Local Search and Virtual Earth maps.
 
For more Local Listing Center information see Mohan Varthakavi's blog, specifically Live Search Maps Released: Live Search Maps Welcomes Business Owners.
September 08

VS 2005 Designer Class Macro for C#

When projects are converted from VS 2003 to VS 2005, component classes are not automatically split out to have the new designer partial classes (e.g. MyForm.cs and MyForm.Designer.cs). 
 
So, I thought I'd throw together a Visual Studio macro that takes care of this for me...  Note: The macro expects the code view for the class to split to be the active VS document.
 
Here's the macro:
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics
Imports System.Windows.Forms
Imports System.IO
Imports System.Text.RegularExpressions
Imports System.Collections.Generic

Public Module Components

    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ' Splits a form or user control in one source file into custom and 
    ' designer partial classes.
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Sub SplitToDesignerClass()

        Dim closeUndoContext As Boolean = False

        ' If necessary, create a new undo context
        If DTE.UndoContext.IsOpen = False Then
            closeUndoContext = True
            DTE.UndoContext.Open("SplitToPartialClass Macro", False)
        End If

        Try
            ' Get the project item name
            Dim projectItem As ProjectItem = DTE.ActiveDocument.ProjectItem
            Dim itemName As String = _
                Path.GetFileNameWithoutExtension(projectItem.Name)
            Dim fileName As String = projectItem.FileNames(1)

            ' Determine if the child designer project item already exists
            Dim designerItemName As String = _
                itemName & ".Designer"
            Dim childItems As ProjectItems = projectItem.ProjectItems
            Dim childItem As ProjectItem
            Dim designerFound As Boolean = False
            For Each childItem In childItems
                If (Path.GetFileNameWithoutExtension(childItem.Name) = _
                    designerItemName) Then
                    designerFound = True
                    Exit For
                End If
            Next

            ' If the designer file does not exist, then create it and add it as a
            ' child project item
            Dim designerFileName As String = _
                Path.Combine(Path.GetDirectoryName(fileName), _
                designerItemName & ".cs")
            If (Not designerFound) Then

                ' Create the file
                Dim designerFile As FileStream = File.Create(designerFileName)
                designerFile.Close()

                Dim designerItem As ProjectItem = _
                    projectItem.ProjectItems.AddFromFile(designerFileName)

                Dim originalElements As CodeElements = _
                    projectItem.FileCodeModel.CodeElements

                ' Add the namespace 
                Dim namesSpaceName As String
                Dim currentElement As CodeElement
                Dim origNamespace As CodeNamespace
                Dim designerNamespace As CodeNamespace
                For Each currentElement In originalElements
                    If (currentElement.Kind = vsCMElement.vsCMElementNamespace) Then
                        origNamespace = CType(currentElement, CodeNamespace)
                        designerNamespace = designerItem.FileCodeModel.AddNamespace( _
                            currentElement.FullName)
                        Exit For
                    End If
                Next

                Dim editPoint As EditPoint

                ' Find the original class 
                Dim origClass As CodeClass2
                For Each currentElement In origNamespace.Children
                    If (currentElement.Kind = vsCMElement.vsCMElementClass) Then
                        origClass = CType(currentElement, CodeClass2)
                        Exit For
                    End If
                Next

                ' Find the InitializeComponent method
                Dim childElement As CodeElement
                Dim initializeMethod As CodeFunction
                For Each childElement In origClass.Children
                    If ((childElement.Kind = vsCMElement.vsCMElementFunction) And _
                    (childElement.Name = "InitializeComponent")) Then
                        initializeMethod = CType(childElement, CodeFunction)
                        Exit For
                    End If
                Next

                If (Not initializeMethod Is Nothing) Then

                    Dim methodText As String = GetCodeElementBody(initializeMethod)

                    ' Find all component members
                    Dim memberAssignments As List(Of String) = New List(Of String)()
                    Dim componentMembers As List(Of CodeVariable) = New List(Of CodeVariable)()
                    Dim regex As Regex = New Regex("this\.(?.+?)\s+=\s+new")
                    Dim matches As MatchCollection = regex.Matches(methodText)
                    Dim match As Match
                    For Each match In matches
                        memberAssignments.Add(match.Groups("Member").Value)
                    Next
                    For Each childElement In origClass.Children
                        If (childElement.Kind = vsCMElement.vsCMElementVariable And _
                        memberAssignments.Contains(childElement.Name)) Then
                            componentMembers.Add(CType(childElement, CodeVariable))
                        End If
                    Next

                    ' Add the partial class
                    Dim namespaceBodyStart As TextPoint = _
                        designerNamespace.GetStartPoint(vsCMPart.vsCMPartBody)
                    editPoint = namespaceBodyStart.CreateEditPoint()
                    editPoint.Insert("public partial class " & _
                        origClass.Name & Environment.NewLine & "{" & _
                        Environment.NewLine & "}" & Environment.NewLine)

                    ' Get the partial class
                    Dim designerClass As CodeClass2 = _
                        CType(designerNamespace.Children.Item(1), CodeClass)

                    ' Add the initialize component method
                    Dim designFunction As CodeFunction = _
                        designerClass.AddFunction( _
                        initializeMethod.Name, _
                        initializeMethod.FunctionKind, initializeMethod.Type)
                    designFunction.Access = vsCMAccess.vsCMAccessPrivate
                    Dim methodBodyStart As TextPoint = _
                    designFunction.GetStartPoint(vsCMPart.vsCMPartBody)
                    editPoint = methodBodyStart.CreateEditPoint()
                    editPoint.Insert(methodText)

                    ' Add the component members
                    Dim componentMember As CodeVariable
                    For Each componentMember In componentMembers
                        Dim codeVariable As CodeVariable = _
                            designerClass.AddVariable( _
                            componentMember.Name, componentMember.Type)
                        codeVariable.Access = componentMember.Access
                    Next

                    ' Format the partial class
                    Dim namespaceBodyEnd As TextPoint = _
                        designerNamespace.GetEndPoint(vsCMPart.vsCMPartBody)
                    editPoint = namespaceBodyStart.CreateEditPoint()
                    editPoint.SmartFormat(namespaceBodyEnd)

                    ' Make the current class a partial class
                    Dim classNameStart As TextPoint = _
                       origClass.GetStartPoint(vsCMPart.vsCMPartHeader)
                    Dim classNameEnd As TextPoint = _
                        origClass.GetStartPoint(vsCMPart.vsCMPartBody)
                    editPoint = classNameStart.CreateEditPoint()
                    editPoint.ReplacePattern(classNameEnd, "class", "partial class")

                    ' Finally, remove the initialize method and component members 
                    ' from the original class
                    origClass.RemoveMember(initializeMethod)
                    For Each componentMember In componentMembers
                        origClass.RemoveMember(componentMember)
                    Next

                End If
            End If

        Catch ex As Exception
            MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace)
        Finally
            ' If an error occured, then we need to make sure that the undo 
            ' context is cleaned up.
            ' Otherwise, the editor can be left in a perpetual undo context
            If (closeUndoContext) Then
                DTE.UndoContext.Close()
            End If
        End Try

    End Sub

    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ' Gets a code element's body text
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Private Function GetCodeElementBody( _
        ByRef codeElement As CodeElement) As String

        Dim startPoint As TextPoint = codeElement.GetStartPoint(vsCMPart.vsCMPartBody)
        Dim endPoint As TextPoint = codeElement.GetEndPoint(vsCMPart.vsCMPartBody)

        Dim editPoint As EditPoint = startPoint.CreateEditPoint()

        Dim text = editPoint.GetText(endPoint)

        Return text

    End Function

End Module
July 29

Converting VS 2003 User Control Projects to 2005

The Test Container for User Control Libraries in Visual Studio 2005 is awesome!  However, I noticed that when Visual Studio 2003 class library projects  are converted up to 2005, they do not automatically get this debugging functionality when they contain user controls.
 
After digging around in the VS program files directory I came across the Windows Control Library project template.  It can be found at Microsoft Visual Studio 8\Common7\IDE\ProjectTemplates\CSharp\Windows\1033\WindowsControlLibrary.zip.
 
Within the item group for the source files to compile (see below) I noticed that there is a service element.  It turns out that that the service with guid 94E38DFF-614B-4cbd-B67C-F211BB35CE8B is the service for the Test Container.  Adding the service XML element within the compilation section of your .csproj file will change it from a plain-old class library to a Windows User Control Library.  Now when the project is debugged through Visual Studio the Test Container pops up. 
 
Example .csproj compilation XML:
<ItemGroup>
  <Compile Include="UserControl1.cs">
   <SubType>UserControl</SubType>
  </Compile>
  <Compile Include="UserControl1.Designer.cs">
   <DependentUpon>UserControl1.cs</DependentUpon>
  </Compile>
  <Compile Include="Properties\AssemblyInfo.cs" />
  <Service Include="{94E38DFF-614B-4cbd-B67C-F211BB35CE8B}" />
 </ItemGroup>