2010-02-01 27 views
9

將我的Visual Studio 2003項目遷移到VS2005(或VS2008)後,我的表單仍然位於單個文件中。使用部分類和設計器文件將Visual Studio 2003表單轉換爲Visual Studio 2005/2008表單

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

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

我已經做了一些手工,但這是非常棘手的,可能會導致一些嚴重的錯誤。

有什麼建議嗎? PS:我使用Microsoft Visual C#2008 快遞版。

回答

7

這似乎是你想要的。

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

NET 2.0中引入的局部類這使得在 Visual Studio 2005和後來的「.designer」文件。也就是說,所有設計者生成的代碼(控件聲明,InitializeComponent 方法等)都可以保存在與常規代碼分開的文件中。 當您在 Visual Studio 2005/2008中打開.NET 1.x Visual Studio 2003 WinForms項目時,它會將您的項目升級到.NET 2.0,只是 好,但不幸的是,它不會將您的WinForms類通過 遷移到新的「.designer」項目結構。

起初我以爲這 將是一個DXCore插件(免費的框架,在其 的CodeRush建)工作,因爲它提供的插件與 代碼的對象模型,它可以用來搶所有正確的成員,並將它們移動到設計器文件中 。在我研究這個之前,雖然我檢查了 這些選項是爲了簡單地將它作爲Visual Studio 宏來實現的。我完全期待不得不使用正則表達式來執行 grep代碼文件來執行任務,但驚喜地發現 發現Visual Studio可擴展性API可用於 宏提供了一個代碼模型(基於.NET CodeDom我假設) 你可以遍歷檢查和操縱底層代碼。 所以,這裏所產生的是什麼「ExtractWinFormsDesignerFile」宏觀 作用:

  • 通過遍歷 ProjectItem.FileCodeModel.CodeElements位於所選項目項(DTE.SelectedItems.Item(1).ProjectItem)第一類
  • 提取物在InitializeComponent和通過遍歷CodeClass.Members處置從所述類方法
  • 提取所有控制字段:即,各個領域,其類型從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顯示宏編輯器)。
要使用:

  • 在Solution Explorer
  • 運行通過顯示宏資源管理器(ALT + F8),並雙擊「ExtractWinFormsDesignerFile」宏選擇Windows窗體的宏。 (顯然 如果你喜歡,你可以將宏連接到一個工具欄按鈕。)
  • 然後系統會提示你手動讓Form類變爲partial(另一點我懶得弄清楚如何讓宏執行): 即改變公共類MyForm的:從到公共部分類 MyForm的:表格
+0

我想我不會在快遞版上工作。 :-( – Jonas 2010-02-01 20:55:33

+1

)你不太可能找到一個可以快速處理的工具,但是,希望這是一次性的 - 你應該能夠下載一個可以處理宏/插件的beta或者eval版本。 – 2010-02-10 05:10:14

2

正如你可能知道,所有的Express版本不支持第三方擴展。不幸的是,我知道沒有任何獨立的工具可以做你正在問的東西。

我已經嘗試將Winform類拆分爲partials類。正如你發現的那樣,這不是一件小事。 This之前有問題。不像Martin's嘗試,我去了另一個方向。我沒有創建設計器文件,而是將現有文件重命名爲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> 

另一種解決方案,我用了簡單的創建一個新的形式,並從舊錶拖動控制試驗到它。這實際上在一定程度上起作用。所有控件都隨其所有屬性一起遷移。沒有遷移的是事件處理程序。這些您必須從舊窗體中剪切並粘貼,然後遍歷每個控件並從窗體設計器重新選擇適當的處理程序。根據表單的複雜性,這可能是一個合理的選擇。

從我個人的經驗來看,支持多個用戶界面最好的方法是保持表單設計簡單,並將業務邏輯與用戶界面完全分開。 MVP Passive view對此很有效。通過將盡可能多的責任委託給演示者類,在不同的UI框架中實現該表單變得微不足道。 WinForms,WebForms,WPF等,對主講者類沒什麼影響。它在接口中看到的所有內容都暴露了它所操作的屬性列表。當然,當你面臨的問題在這裏和現在時,世界上所有的本能都無濟於事。

相關問題