使用部分类和设计器文件将 Visual Studio 2003 表单转换为 Visual Studio 2005/2008 表单

Posted

技术标签:

【中文标题】使用部分类和设计器文件将 Visual Studio 2003 表单转换为 Visual Studio 2005/2008 表单【英文标题】:Convert Visual Studio 2003 forms to Visual Studio 2005/2008 forms using partial classes and Designer files 【发布时间】:2011-01-11 21:06:30 【问题描述】:

将我的 Visual Studio 2003 项目迁移到 VS2005(或 VS2008)后,我的表单仍将位于单个文件中。

VS2005 和 VS2008 上的新表单是使用部分类创建的,其中编辑器生成的所有代码都保存在 Designer.cs 文件中。

由于 VS2005 表单创建是一种更好的表单处理方式,我想知道是否有办法将我所有的旧单文件表单转换为 VS2005 部分类方法。

我已经手动完成了一些,但这非常棘手,可能会导致一些严重的错误。

有什么建议吗? PS:我使用的是 Microsoft Visual C# 2008 Express 版。

【问题讨论】:

【参考方案1】:

这似乎是你想要的。

Converting Visual Studio 2003 WinForms to Visual Studio 2005/2008 partial classes :

NET 2.0 引入了部分类,可以在 Visual Studio 2005 及更高版本。也就是说,所有的视觉 设计器生成的代码(控件声明、InitializeComponent 方法等)可以保存在与常规代码分开的文件中。 当您打开 .NET 1.x Visual Studio 2003 WinForms 项目时 Visual Studio 2005/2008 它将您的项目升级到 .NET 2.0 很好,但不幸的是它不会迁移你的 WinForms 类 到新的“.designer”项目结构。

一开始我是这么想的 将是 DXCore 插件的工作(免费框架 CodeRush 是构建的),因为它为插件提供了一个对象模型 可用于抓取所有正确成员并移动它们的代码 进入设计器文件。在我调查之前,虽然我检查过 将其简单地实现为 Visual Studio 的选项是什么 宏。我完全期望必须使用正则表达式来 grep 代码文件执行任务,却惊喜连连 找到可用于的 Visual Studio 可扩展性 API 宏提供了一个代码模型(基于我假设的 .NET CodeDom) 你可以遍历它来检查和操作底层代码。 所以,这就是生成的“ExtractWinFormsDesignerFile”宏 确实:

通过遍历 ProjectItem.FileCodeModel.CodeElements 通过遍历 CodeClass.Members 从类中提取 InitializeComponent 和 Dispose 方法 提取所有控件字段:即类型派生自 System.Windows.Forms.Control 或 System.ComponentModel.Container 的所有字段 或类型名称以 System.Windows.Forms 开头的 将所有提取的代码放入一个新的“FormName.Designer.cs”文件中。

目前这只是 C# - 它可以很容易地转换为 生成的 VB.NET 代码或改编使用 FileCodeModel 正确和 可能在生成时以与语言无关的方式创建代码 设计器文件。我在生成设计器时采取了捷径 文件作为字符串并将其直接写入文件。

要“安装”: download the macro text:

    ' -------------------------------------------------------------------------
    ' Extract WinForms Designer File Visual Studio 2005/2008 Macro
    ' -------------------------------------------------------------------------
    ' Extracts the InitializeComponent() and Dispose() methods and control
    ' field delarations from a .NET 1.x VS 2003 project into a VS 2005/8 
    ' style .NET 2.0 partial class in a *.Designer.cs file. (Currently C# 
    ' only)
    ' 
    ' To use: 
    '  * Copy the methods below into a Visual Studio Macro Module (use 
    '    ALT+F11 to show the Macro editor)
    '  * Select a Windows Form in the Solution Explorer
    '  * Run the macro by showing the Macro Explorer (ALT+F8) and double
    '    clicking the 'ExtractWinFormsDesignerFile' macro.
    '  * You will then be prompted to manually make the Form class partial: 
    '    i.e. change "public class MyForm : Form"
    '          to
    '             "public partial class MyForm : Form"
    '
    ' Duncan Smart, InfoBasis, 2007
    ' -------------------------------------------------------------------------

    Sub ExtractWinFormsDesignerFile()
        Dim item As ProjectItem = DTE.SelectedItems.Item(1).ProjectItem
        Dim fileName As String = item.FileNames(1)
        Dim dir As String = System.IO.Path.GetDirectoryName(fileName)
        Dim bareName As String = System.IO.Path.GetFileNameWithoutExtension(fileName)
        Dim newItemPath As String = dir & "\" & bareName & ".Designer.cs"

        Dim codeClass As CodeClass = findClass(item.FileCodeModel.CodeElements)
        Dim namespaceName As String = codeClass.Namespace.FullName

        On Error Resume Next ' Forgive me :-)
        Dim initComponentText As String = extractMember(codeClass.Members.Item("InitializeComponent"))
        Dim disposeText As String = extractMember(codeClass.Members.Item("Dispose"))
        Dim fieldDecls As String = extractWinFormsFields(codeClass)
        On Error GoTo 0

        System.IO.File.WriteAllText(newItemPath, "" _
          & "using System;" & vbCrLf _
          & "using System.Windows.Forms;" & vbCrLf _
          & "using System.Drawing;" & vbCrLf _
          & "using System.ComponentModel;" & vbCrLf _
          & "using System.Collections;" & vbCrLf _
          & "" & vbCrLf _
          & "namespace " & namespaceName & vbCrLf _
          & "" & vbCrLf _
          & "   public partial class " & codeClass.Name & vbCrLf _
          & "   " & vbCrLf _
          & "       #region Windows Form Designer generated code" & vbCrLf _
          & "       " & fieldDecls & vbCrLf _
          & "       " & initComponentText & vbCrLf _
          & "       #endregion" & vbCrLf & vbCrLf _
          & "       " & disposeText & vbCrLf _
          & "   " & vbCrLf _
          & "" & vbCrLf _
          )
        Dim newProjItem As ProjectItem = item.ProjectItems.AddFromFile(newItemPath)
        On Error Resume Next
        newProjItem.Open()
        DTE.ExecuteCommand("Edit.FormatDocument")
        On Error GoTo 0

        MsgBox("TODO: change your class from:" + vbCrLf + _
               "  ""public class " + codeClass.FullName + " : Form""" + vbCrLf + _
               "to:" + _
               "  ""public partial class " + codeClass.FullName + " : Form""")
    End Sub

    Function findClass(ByVal items As System.Collections.IEnumerable) As CodeClass
        For Each codeEl As CodeElement In items
            If codeEl.Kind = vsCMElement.vsCMElementClass Then
                Return codeEl
            ElseIf codeEl.Children.Count > 0 Then
                Dim cls As CodeClass = findClass(codeEl.Children)
                If cls IsNot Nothing Then
                    Return findClass(codeEl.Children)
                End If
            End If
        Next
        Return Nothing
    End Function

    Function extractWinFormsFields(ByVal codeClass As CodeClass) As String

        Dim fieldsCode As New System.Text.StringBuilder

        For Each member As CodeElement In codeClass.Members
            If member.Kind = vsCMElement.vsCMElementVariable Then
                Dim field As CodeVariable = member
                If field.Type.TypeKind <> vsCMTypeRef.vsCMTypeRefArray Then
                    Dim fieldType As CodeType = field.Type.CodeType
                    Dim isControl As Boolean = fieldType.Namespace.FullName.StartsWith("System.Windows.Forms") _
                       OrElse fieldType.IsDerivedFrom("System.Windows.Forms.Control") _
                       OrElse fieldType.IsDerivedFrom("System.ComponentModel.Container")
                    If isControl Then
                        fieldsCode.AppendLine(extractMember(field))
                    End If
                End If
            End If
        Next
        Return fieldsCode.ToString()
    End Function

    Function extractMember(ByVal memberElement As CodeElement) As String
        Dim memberStart As EditPoint = memberElement.GetStartPoint().CreateEditPoint()
        Dim memberText As String = String.Empty
        memberText += memberStart.GetText(memberElement.GetEndPoint())
        memberStart.Delete(memberElement.GetEndPoint())
        Return memberText
    End Function

并将方法复制到 Visual Studio 宏模块(使用 ALT+F11 显示宏编辑器)。 使用方法:

在解决方案资源管理器中选择一个 Windows 窗体 通过显示宏资源管理器 (ALT+F8) 并双击“ExtractWinFormsDesignerFile”宏来运行宏。 (明显地 如果您愿意,可以将宏连接到工具栏按钮。) 然后系统会提示您手动将 Form 类设为部分(还有一点我太懒了,没有弄清楚如何让宏去做): 即更改 public class MyForm : Form to public partial class 我的表格:表格

【讨论】:

您不太可能找到适用于 express 的工具。但是,希望这是一次性的 - 您应该能够下载将处理宏/插件的 beta 或 eval 版本。【参考方案2】:

您可能知道,所有 Express 版本都不支持第三方扩展。不幸的是,我知道没有可以满足您要求的独立工具。

我已经尝试将 Winform 类拆分为部分类。正如您所发现的,这不是一项微不足道的工作。 This 之前已经提出过问题。与Martin's 的尝试不同,我走向了另一个方向。我没有创建设计器文件,而是将现有文件重命名为 MyForm.Designer.cs 并创建了一个新的 MyForm.cs 文件。然后我以类似的方式继续,将“代码背后”而不是设计器代码移动到我的新类中。

这两种技术的一个症结在于,未来对表单的更改仍然不会在正确的类文件中生成。这是因为项目文件仍然无法识别要链接在一起的两个文件。您唯一的选择是在文本编辑器中手动编辑项目文件。查找以下内容:

<Compile Include="MyForm.Designer.cs">
  <SubType>Form</SubType>
</Compile>

&lt;SubType&gt;...&lt;/SubType&gt; 替换为&lt;DependentUpon&gt;MyForm.cs&lt;/DependentUpon&gt;,最终结果如下所示:

<Compile Include="MyForm.Designer.cs">
  <DependentUpon>MyForm.cs</DependentUpon>
</Compile>

我尝试过的另一个解决方案是简单地创建一个新表单并将控件从旧表单拖动到它。这实际上在一定程度上起作用。所有控件连同它们的所有属性一起迁移。没有迁移的是事件处理程序。这些您必须从旧表单中剪切和粘贴,然后遍历每个控件并从表单设计器中重新选择适当的处理程序。根据表单的复杂性,这可能是一个合理的选择。

根据我自己支持多个 UI 的个人经验,最好的方法是保持表单设计简单,并将业务逻辑与 UI 完全分离。 MVP Passive view 对此非常有效。通过将尽可能多的责任委托给演示者类,在不同的 UI 框架中实现表单变得微不足道。 WinForms、WebForms、WPF 等,它对演示者类几乎没有影响。它在一个界面中看到的所有内容都暴露了它所操作的属性列表。当然,当您面临的问题就在此时此地时,世界上所有应该做的事情都无济于事。

【讨论】:

以上是关于使用部分类和设计器文件将 Visual Studio 2003 表单转换为 Visual Studio 2005/2008 表单的主要内容,如果未能解决你的问题,请参考以下文章

Visual Studio 设计器无法加载文件或程序集

visualstudio的窗体设计中led在哪里

Visual Studio 2008 Windows 窗体设计器如何兼容 QVGA 和 VGA?

visual-studio-code 中的自动右括号不适用于 js 和 jsx 文件

部分类/部分类文件

在 Visual Studio 2008 中使用设计器将逗号分隔列表作为参数传递给 db2 查询的 IN 子句