簡體   English   中英

使用部分類和Designer文件將Visual Studio 2003表單轉換為Visual Studio 2005/2008表單

[英]Convert Visual Studio 2003 forms to Visual Studio 2005/2008 forms using partial classes and Designer files

將我的Visual Studio 2003項目遷移到VS2005(或VS2008)后,我的表單仍然在單個文件中。

VS2005和VS2008上的新表單是使用部分類創建的,其中編輯器生成的所有代碼都保存在Designer.cs文件中。

由於VS2005表單創建是一種更好的處理表單的方法,我想知道是否有一種方法可以將所有舊的單文件格式轉換為VS2005分類方法。

我已經完成了一些手工操作,但這非常棘手,可能導致一些嚴重的錯誤。

有什么建議? PS:我正在使用Microsoft Visual C#2008 Express Edition。

這似乎是你想要的。

將Visual Studio 2003 WinForms轉換為Visual Studio 2005/2008部分類

NET 2.0引入了部分類,它在Visual Studio 2005及更高版本中啟用“.designer”文件。 也就是說,所有可視化設計器生成的代碼(控件聲明,InitializeComponent方法等)都可以保存在與常規代碼分開的文件中。 當您在Visual Studio 2005/2008中打開.NET 1.x Visual Studio 2003 WinForms項目時,它會將您的項目升級到.NET 2.0,但不幸的是它不會將您的WinForms類遷移到新的“。設計師“項目結構。

最初我認為這將是DXCore插件(構建CodeRush的免費框架)的工作,因為它為插件提供了代碼的對象模型,可用於獲取所有正確的成員並移動它們進入設計師檔案。 在我調查之前,我檢查了將它作為Visual Studio宏實現的選項。 我完全期望必須使用正則表達式來grep代碼文件來執行任務,但是驚喜地發現可用於宏的Visual Studio可擴展性API提供了代碼模型(基於.NET CodeDom我假設) )您可以遍歷以檢查和操作底層代碼。 那么,這就是生成的“ExtractWinFormsDesignerFile”宏的作用:

  • 通過遍歷ProjectItem.FileCodeModel.CodeElements找到所選項目項(DTE.SelectedItems.Item(1).ProjectItem)中的第一個類
  • 通過遍歷CodeClass.Members從類中提取InitializeComponent和Dispose方法
  • 提取所有控制字段:即,類型派生自System.Windows.Forms.Control或System.ComponentModel.Container或其類型名稱以System.Windows.Forms開頭的所有字段
  • 將所有提取的代碼放入新的“FormName.Designer.cs”文件中。

這只是目前的C# - 它可以很容易地轉換為生成的VB.NET代碼或者適當地使用FileCodeModel,並且可能在生成設計器文件時以與語言無關的方式創建代碼。 我采用了一種快捷方式,只是將設計器文件生成為字符串並將其直接寫入文件。

要“安裝”: 下載宏文本

    ' -------------------------------------------------------------------------
    ' 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類部分(另一點我懶得弄清楚如何讓宏做):即將公共類MyForm:Form更改為public partial class MyForm:Form

您可能知道,所有Express版本都不支持第三方擴展。 不幸的是,我知道沒有獨立的工具可以做你想要的。

我已經嘗試將Winform類拆分為partials類。 正如您所發現的那樣,這不是一項微不足道的事情。 之前已經問過這個問題。 馬丁的嘗試不同,我走向另一個方向。 我沒有創建設計器文件,而是將現有文件重命名為MyForm.Designer.cs並創建了一個新的MyForm.cs文件。 然后我以類似的方式進行,將“代碼隱藏”而不是設計器代碼移動到我的新類中。

使用這些技術中的任何一個的一個難點是未來對表單的更改仍然不會在正確的類文件中生成。 這是因為項目文件仍然無法識別要鏈接在一起的兩個文件。 您唯一的選擇是在文本編輯器中手動編輯項目文件。 尋找以下內容:

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

<SubType>...</SubType>替換為<DependentUpon>MyForm.cs</DependentUpon>以便最終結果如下所示:

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

我嘗試的另一個解決方案是簡單地創建一個新表單並將控件從舊表單拖動到它。 這實際上在一定程度上起作用。 所有控件及其所有屬性都已遷移。 沒有遷移的是事件處理程序。 這些你必須從舊表單剪切和粘貼,然后遍歷每個控件並從表單設計器重新選擇適當的處理程序。 根據表單的復雜程度,這可能是一個合理的選擇。

根據我自己支持多個UI的個人經驗,最好的方法是保持表單設計簡單,並將業務邏輯與UI完全分開。 MVP被動視圖對此非常有效。 通過將盡可能多的責任委托給演示者類,在不同的UI框架中實現表單變得微不足道。 WinForms,WebForms,WPF等,它對演示者類沒什么區別。 它在界面中看到它暴露了它操作的屬性列表。 當然,當你面臨的問題在這里和現在時,世界上所有的應有的意志都無濟於事。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM