2010-02-01 16 views
9

Después de migrar mis proyectos de Visual Studio 2003 a VS2005 (o VS2008), mis formularios seguirían estando dentro de un único archivo.Convertir formularios de Visual Studio 2003 a formularios de Visual Studio 2005/2008 utilizando clases parciales y archivos de Designer

Los formularios nuevos en VS2005 y VS2008 se crean utilizando clases parciales donde todo el código generado por el editor se guarda en el archivo Designer.cs.

Dado que el formulario VS2005 crea una forma mucho mejor de tratar con formularios, me gustaría saber si hay una forma de convertir todos mis formularios antiguos de un solo archivo al método de clase parcial VS2005.

He hecho algunas cosas a mano, pero esto es muy complicado y puede provocar algunos errores graves.

¿Alguna sugerencia? PD: estoy usando Microsoft Visual C# 2008 Express Edición.

Respuesta

7

Esto parece ser lo que quieres.

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

NET 2.0 clases parciales introducidas que permite que los archivos “.designer” en Visual Studio 2005 y más adelante. Es decir, todo el código visual generado por el diseñador (declaraciones de control, el método InitializeComponent , etc.) puede guardarse en un archivo separado de su código normal. Al abrir un proyecto .NET 1.x Visual Studio 2003 WinForms en Visual Studio 2005/2008 actualizará su proyecto a .NET 2.0 solo bien, pero desafortunadamente no migra sus clases WinForms a más de a la nueva estructura del proyecto ".designer".

Inicialmente pensé que esto sería un trabajo para un plug-in DXCore (el marco libre donde se eleva el CodeRush), ya que proporciona plug-ins con un modelo de objetos del código que podría ser utilizado para agarrar todos los miembros correctos y moverlos en un archivo de diseñador. Antes de analizar esto, sin embargo, verifiqué cuáles eran las opciones para implementarlo simplemente como una macro de Visual Studio . Esperaba tener que usar una expresión regular en grep el archivo de código para realizar la tarea, pero me sorprendió gratamente para encontrar que la API de extensibilidad de Visual Studio disponible para las macros proporciona un modelo de código (basado en .NET CodeDom I supongo) que puede recorrer para inspeccionar y manipular el código subyacente. lo tanto, aquí es lo que el resultado “ExtractWinFormsDesignerFile” macro hace:

  • localiza la primera clase en el elemento de proyecto seleccionado (DTE.SelectedItems.Item (1) .ProjectItem) por la que atraviesa los ProjectItem.FileCodeModel.CodeElements
  • extrae el InitializeComponent y disponer métodos de la clase por CodeClass.Members atraviesan
  • extrae todos los campos de control: es decir, todos los campos cuyo tipo se deriva de System.Windows.Forms.Control o System.ComponentModel.Container o cuya El nombre del tipo comienza con System.Windows.Forms
  • Pone todo el código extraído en un nuevo archivo "FormName.Designer.cs".

Ésta es actualmente C# única - que fácilmente podría ser convertido en código VB.NET generada o uso adaptado el FileCodeModel correctamente y quizá crear el código de una manera independiente del idioma cuando se genera el archivo de diseño. Tomé un atajo para generar el archivo de diseñador como una cadena y escribirlo directamente en un archivo.

para “instalar”: 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 

y copiar los métodos en un Visual Studio módulo de macro (uso ALT + F11 para mostrar el editor de macros).
de usar:

  • seleccionar un formulario de Windows en el Explorador de soluciones
  • ejecutar la macro que muestra el Explorador de macros (ALT + F8) y haga doble clic en la macro ‘ExtractWinFormsDesignerFile’. (Obviamente puede conectar la macro a un botón de la barra de herramientas si lo desea)
  • Luego se le pedirá que haga manualmente la clase Form (otro bit fui demasiado flojo para averiguar cómo hacer que la macro lo haga)): es decir, cambio MiFormulario clase pública: Formulario de clase parcial pública MiFormulario: Formulario
+0

Creo que no funcionaré en las ediciones express. :-( – Jonas

+1

Es poco probable que encuentre una herramienta que funcione en Express. Sin embargo, esperamos que esto sea una sola vez: debería poder descargar una versión beta o eval que maneje macros/plugins. –

2

Como usted probablemente sabe, todas las ediciones express no son compatibles con las extensiones de terceros. Lamentablemente, no conozco herramientas independientes que puedan hacer lo que me piden.

He experimentado con la división de una clase Winform en clases de parciales. Como descubriste, no es una tarea trivial. This pregunta se ha preguntado antes. A diferencia del intento Martin's, fui en la otra dirección. En lugar de crear un archivo de diseñador, cambié el nombre del archivo existente a MyForm.Designer.cs y creé un nuevo archivo MyForm.cs. Luego procedí de una manera similar, moviendo el "código detrás" en lugar del código de diseñador a mi nueva clase.

El único punto de fricción con cualquiera de estas técnicas es que los cambios futuros en el formulario aún no se generan en el archivo de clase correcto. Esto se debe a que el archivo de proyecto aún no reconoce los dos archivos que se vincularán entre sí. Su única opción es editar manualmente el archivo del proyecto en un editor de texto. Busque los siguientes:

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

Vuelva a colocar la <SubType>...</SubType> con <DependentUpon>MyForm.cs</DependentUpon> lo que el resultado final es parecido:

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

Otra solución Experimenté con fue la simple creación de una forma nueva y arrastrando los controles de la forma antigua lo. Esto realmente funcionó en cierta medida. Todos los controles migraron junto con todas sus propiedades. Lo que no migró fueron los controladores de eventos. Debería cortar y pegar desde la forma anterior, luego pasar por cada control y volver a seleccionar el controlador apropiado del diseñador de formularios. Dependiendo de la complejidad del formulario, esta podría ser una alternativa razonable.

A partir de mis propias experiencias personales que admiten varias IU, lo mejor es mantener el diseño de formularios simple y separar por completo la lógica empresarial de la IU. El MVP Passive view funciona bastante bien para esto. Al delegar la mayor parte de la responsabilidad en una clase de presentador, resulta trivial implementar el formulario en un marco de interfaz de usuario diferente. WinForms, WebForms, WPF, etc., tiene poca importancia para la clase de presentador. Todo lo que ve en una interfaz expone una lista de propiedades que manipula. Por supuesto, todo lo que cabría en el mundo no ayudará cuando el problema al que se enfrenta sea aquí y ahora.

Cuestiones relacionadas