Click here to Skip to main content
15,879,095 members
Articles / Programming Languages / Visual Basic

A Visual Studio add-in to move Windows Forms Designer generated code from a .vb file to a .Designer.vb file

Rate me:
Please Sign up or sign in to vote.
4.04/5 (11 votes)
19 Jan 2013CPOL7 min read 47.1K   808   12   12
Convert VB.NET 2003 Windows Forms Designer section of Windows Form Public Class files to Partial Class files.

Introduction

This article provides instructions for installing and using a Visual Studio 2012 add-in to move Visual Studio 2003 Windows Forms Designer generated code from the Public Class file to a Partial Class file. In addition, I tell the story of how I created the add-in.

When Visual Studio 2005 was released, the Visual Studio 2003 Windows Forms Designer generated code was removed from the .vb file and placed in a separate .Designer.vb file. Visual Studio 2012 still accepts the Windows Forms Designer generated code in the .vb file for an existing Project. As part of my Visual Studio 2012 learning process, I wanted to separate the Windows Forms Designer generated code into a Partial Class .Designer.vb file.

The Macro

I found several versions of a Visual Studio Macro for doing this at http://www.nathanpjones.com/wp/2010/02/converting-vb-net-2003-winforms-to-20052008-partial-classes. Unfortunately, I found that the Macros feature had been removed from Visual Studio 2012. After seeing the original author’s comment to “dig into it to get it to work the way you want", I decided to turn it into a Visual Studio Add-In. Something new to learn!

I want to express my thanks to the original Macro developer and to those that subsequently submitted their own amendments. That code gave me a jumpstart on this project. The original Macro traversed the Visual Studio automation object model of the selected Windows Form .vb file to locate variable declarations that were initialized by code within the Sub InitializeComponent procedure and to locate both the Sub InitializeComponent and Sub Dispose procedures. These along with a Partial Class clause are used to create a new .Designer.vb file. A subsequent version of the Macro, contributed by another programmer, selected variables derived from System.Windows.Forms.Control or System.ComponentModel.IContainer.

Background

Use this Visual Studio add-in to move Windows Form Designer generated code from a Public Class .vb file to a Partial Class .Designer.vb file.

The ConvertVBFiles VB.NET Project associated with his article is compiled to process all Windows Forms within a selected project. A conditional compilation option is provided to allow you to compile your version to only convert the currently selected Windows Form. Be sure to create a backup of your Visual Studio Solution/Project before attempting to use this Visual Studio Add-In.

Using the code

A compiled version of ConvertVBFiles.dll is included in the ZIP file. Skip steps 2 and 3 if you want to use the ConvertVBFiles.dll as-is with the conditional compilation declaration #CONVERT_ALL_FILES_IN_SELECTED_PROJECT = True.

  1. Extract the ConvertVBFiles Project source code into C:\Users\<USERNAME>\Documents\Visual Studio 2012\Projects.
  2. Edit the value of #Const CONVERT_ALL_FILES_IN_SELECTED_PROJECT = True to True or False.
    • True processes all Windows Forms within a Project.
    • False processes only the selected Windows Form.
  3. Compile your version of ConvertVBFiles.DLL.
  4. Extract the ConvertVBFile.AddIn file into C:\Users\<USERNAME>\Documents\Visual Studio 2012\Addins.
  5. Edit the ConvertVBFile.AddIn file replacing <USERNAME> with your username.
  6. XML
    <?xml version="1.0" encoding="UTF-16" standalone="no"?>
    <Extensibility xmlns="http://schemas.microsoft.com/AutomationExtensibility">
        <HostApplication>
            <Name>Microsoft Visual Studio</Name>
            <Version>11.0</Version>
        </HostApplication>
        <Addin>
            <FriendlyName>Convert VB 'Windows Form Designer generated code' Region to a separate *.Designer.vb file</FriendlyName>
            <Description>Convert VB 'Windows Form Designer generated code' Region to a separate *.Designer.vb file</Description>
            <Assembly>c:\users\<USERNAME>\documents\visual studio 2012\Projects\ConvertVBFiles\ConvertVBFiles\bin\ConvertVBFiles.dll</Assembly>
            <FullClassName>ConvertVBFiles.ConvertVBFiles</FullClassName>
            <LoadBehavior>0</LoadBehavior>
            <CommandPreload>1</CommandPreload>
            <CommandLineSafe>0</CommandLineSafe>
        </Addin>
    </Extensibility>

If you compiled your version with CONVERT_ALL_FILES_IN_SELECTED_PROJECT set to True, with your Solution open, select a Project and then click Tools, Convert to Designer Partial Class. The Add-In will iterate through all of the .VB forms, converting those that contain Windows Form Designer generated code and then display a Message Box detailing what it did.

If you compiled your version with CONVERT_ALL_FILES_IN_SELECTED_PROJECT set to False, with your Solution open, select Windows Form file within a Project and then click Tools, Convert to Designer Partial Class. The Add-In will convert that file and display a Message Box detailing what it did.

Removal

To remove the ConvertVBFiles add-in from Visual Studio, rename the ConvertVBFiles.AddIn extension in the C:\Users\<USERNAME>\Documents\Visual Studio 2012\Addins directory or delete the ConvertVBFile.Addin file.

Points of Interest

Conveniently, Visual Studio 2012 provides an Extensibility Project Type in the New Project dialog. I used this to start my new Add-In project. I pasted the Macro source into a new Sub ExtractWinFormsDesignerFile procedure in my new project and called it from the generated Sub Exec procedure.

I cleaned up a few syntax issues, added some Debug.WriteLine statements to help me learn the process flow, added a few breakpoints and proceeded to start testing. I found a few cases where the object model yielded Nothing values for an item. I added checks using IsNothing() to ignore these items. The version of the Macro code that I used moved some items that should not have been moved. For example, if I had declared a variable derived from something in System.Windows.Form outside of the Windows Form Designer generated code region, it got moved and it shouldn’t have been moved. An example is a Property declaration for a variable of type ListView.SelectedIndexCollection.

At this point, I had selected variable declarations using the following nested If statements.
VB
If (member.Kind = vsCMElement.vsCMElementVariable) Then
    Dim objDeclaration As CodeVariable = DirectCast(member, CodeVariable)
    Dim objFieldType As CodeType = objDeclaration.Type.CodeType
    If Not IsNothing(objFieldType) Then
        If Not IsNothing(objFieldType.Namespace) Then
            Dim isControl As Boolean = objFieldType.Namespace.FullName.StartsWith("System.Windows.Forms")
            Debug.WriteLine("Namespace=" & objFieldType.Namespace.FullName)
            If isControl OrElse objFieldType.IsDerivedFrom("System.ComponentModel.IContainer") Then
                Debug.WriteLine("Added " & objFieldType.Namespace.FullName)
                strWindowsFormsControlsDeclarations.AppendLine(extractMember(member))
                intItemsConvertedCount += 1
            End If
        End If
    End If
End If

A Human Could Tell Which Code to Move

I decided to take advantage of the fact that the object model exposes the absolute character offset of each Sub procedure and each variable declaration. I used the offsets to determine if a variable declaration was within the Windows Form Designer generated code region. This strategy would take advantage of the order in which the Visual Studio 2003 Windows Form Designer wrote out the generated code.

This is the order in which the Visual Studio 2003 Windows Form Designer creates the generated code:

VB
Public Class MainForm
    Inherits System.Windows.Forms.Form

    #Region " Windows Form Designer generated code "
 
    Public Sub New()
    …
    End Sub

    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
    …
    End Sub

    …
    … Windows Form Designer generated variable declarations here …
    …

    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
    …
    End Sub

    Protected Overrides Sub Finalize()
    …
    End Sub

I added a check that the absolute character offset of a variable declaration was less than the absolute character offset of the Sub InitializeComponent procedure and greater than the character offset of either Sub New or Sub Dispose. If so, the variable declaration is moved to the new .Designer.vb file. If Dispose or New are not present, I use zero as their offset value. Doing this creates the small possibility that someone may have declared a System.Windows.Form-derived variable declaration before the Windows Form Designer generated code region. If they did, that variable declaration will be moved also but could easily be moved back with cut and paste.

VB
If (member.Kind = vsCMElement.vsCMElementVariable) Then
    Dim objDeclaration As CodeVariable = DirectCast(member, CodeVariable)
    Dim objFieldType As CodeType = objDeclaration.Type.CodeType
    If Not IsNothing(objFieldType) Then
        If Not IsNothing(objFieldType.Namespace) Then
            Dim isControl As Boolean = objFieldType.Namespace.FullName.StartsWith("System.Windows.Forms")
            ' Character offset of this variable's declaration
            Dim intOffset As Integer = objDeclaration.StartPoint.AbsoluteCharOffset
            Debug.WriteLine("Namespace=" & objFieldType.Namespace.FullName)
            If isControl OrElse objFieldType.IsDerivedFrom("System.ComponentModel.IContainer") Then
                If intOffset_InitializeComponent > intOffset AndAlso (intOffset_Dispose < _
                            intOffset OrElse intOffset_New < intOffset) Then
                    Debug.WriteLine("Added " & objFieldType.Namespace.FullName)       
                    strWindowsFormsControlsDeclarations.AppendLine(extractMember(member))
                    intItemsConvertedCount += 1
                End If
            End If
        End If
    End If
End If

A Friend WithEvents

During testing, I found a few forms where I had declared some System.Windows.Forms-derived variables before the Windows Form generated code region. I made the following change to the Boolean statement that initializes the IsControl variable. The check of the Access property ensures that Friend and WithEvents are present. This further reduces the probability that a variable declaration from outside of the Windows Form Designer generated code region will be erroneously moved to the new .Designer.vb file.

Before

VB
Dim isControl As Boolean = objFieldType.Namespace.FullName.StartsWith("System.Windows.Forms")

After

VB
Dim isControl As Boolean = objFieldType.Namespace.FullName.StartsWith("System.Windows.Forms") AndAlso _
        CBool(objDeclaration.Access And (vsCMAccess.vsCMAccessWithEvents + vsCMAccess.vsCMAccessProject))

Visual Studio Tools Menu

I was experiencing an occasional problem where the Add-In would not put its menu item within the Visual Studio Tools menu. I think this was caused by running in Debug Mode, creating a second instance of Visual Studio (DEVENV.EXE) and not checking the checkboxes in Tools, Manage Add-Ins. I found that if I checked the check boxes, the DLL could not be replaced when I recompiled during testing. I changed one line of code within the Extensibility Project Type-provided code to allow the DLL another opportunity to create the Tools menu item. Within the Sub OnConnection procedure, I made the following change to cause the menu item add code to execute after startup.

Before

VB
If connectMode = ext_ConnectMode.ext_cm_UISetup Then

After

VB
If connectMode = ext_ConnectMode.ext_cm_UISetup OrElse connectMode = ext_ConnectMode.ext_cm_AfterStartup Then

Productivity Improvement

I continued to do testing and cleanup. My final enhancement was to use the conditional compilation feature to allow compiling a version of the Add-In that would iterate through all of the .vb files in a selected Project within the Solution.

Convert only the selected Windows Form within a Project

VB
#Const CONVERT_ALL_FILES_IN_SELECTED_PROJECT = False

Convert all Windows Forms within the selected Project

VB
#Const CONVERT_ALL_FILES_IN_SELECTED_PROJECT = True

PrintDocument

A few days after writing the initial version of this article, I found another type of Windows Form Designer generated variable declaration in one of my programs. To move this item from the .vb file to the .Designer.vb file, I changed the IsControl initialization to the following.

VB
Dim isControl As Boolean = (objFieldType.Namespace.FullName.StartsWith("System.Windows.Forms") OrElse _
	objFieldType.Namespace.FullName.StartsWith("System.Drawing.Printing")) AndAlso _
	CBool(objDeclaration.Access And (vsCMAccess.vsCMAccessWithEvents + vsCMAccess.vsCMAccessProject))

History

  • 01-15-2013: Initial version.
  • 01-19-2013: Added check to handle PrintDocument declaration (Namespace: System.Drawing.Printing).

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Retired
United States United States
I’m retired. When I started my career, programming projects consisted of plugging wires into plug boards to create punch card processing applications to be run on electrical accounting machine like the IBM 402, 407, 085, 088, 514, 519, etc. From there, I moved to writing SPS and Autocoder applications on an IBM 1401 with 4K of memory eventually upgraded to 16K of memory. After many years of migrating my skills to various languages on various hardware platforms, I became an Information Technology Director where I didn’t need to program anymore. So, starting in 1996, I volunteered my time with a local community cable television organization and built some applications to help them run their operations. Originally in Clipper Summer 1987 and later Clipper 5.2, I migrated and enhanced those applications to VB .NET 2003 in 2003. I retired from my full-time job in 2010. Since then, I have continued to support the local community cable tv organization's applications. In 2013, I migrated the VB .NET 2003 Solution to VB .NET 2012 so that it can run on 64-bit computers and interact with Microsoft Office 2010. The upgrade went smoothly. In mid 2013, I developed a VB .NET 2012 application for them to download election results data from the Secretary of State's web site, format the results and send them to a VizRT character generator for on-air display.

Comments and Discussions

 
QuestionHow to use in VS 2017 ? Pin
Member 1291473225-Nov-18 19:48
Member 1291473225-Nov-18 19:48 
QuestionDoes this function in VS2010? Pin
ninefofo16-Dec-13 7:31
ninefofo16-Dec-13 7:31 
AnswerRe: Does this function in VS2010? Pin
Mike Meinz16-Dec-13 10:30
Mike Meinz16-Dec-13 10:30 
SuggestionDo plan to provide similar plugin for C#? Pin
3soft16-Oct-13 20:26
3soft16-Oct-13 20:26 
GeneralRe: Do plan to provide similar plugin for C#? Pin
Mike Meinz17-Oct-13 1:45
Mike Meinz17-Oct-13 1:45 
GeneralThanks For the Article.... Very Helpful.... Pin
Raja Sekhar S11-Jun-13 1:07
Raja Sekhar S11-Jun-13 1:07 
QuestionThanks for this Pin
Member 19205598-Apr-13 7:24
Member 19205598-Apr-13 7:24 
QuestionExtensibility ? Pin
Franjo Markovic18-Feb-13 13:19
Franjo Markovic18-Feb-13 13:19 
AnswerRe: Extensibility ? Pin
Mike Meinz18-Feb-13 15:46
Mike Meinz18-Feb-13 15:46 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA16-Feb-13 19:27
professionalȘtefan-Mihai MOGA16-Feb-13 19:27 
GeneralMy vote of 5 Pin
_Vitor Garcia_6-Feb-13 0:37
_Vitor Garcia_6-Feb-13 0:37 
QuestionGood job Pin
Terence Wallace21-Jan-13 1:35
Terence Wallace21-Jan-13 1:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.