Etiqueta: .NET core

  • Compilar código en .NET Core (.NET 5.0) para consola y Windows Forms

    Pues eso… usando la aplicación que te mostré el otro día (Compilar y ejecutar versión para .NET Core (.NET 5.0)) y después de hacer varias pruebas con otra DLL que compila el código y lo ejecuta sin usar Process.Start, al menos si es una aplicación de consola, (ya que para ejecutar las de Windows Forms, al menos hasta lo que yo he probado, solo puedo lanzarla usando Process.Start); al final me he quedado con la llamada a dotnet para crear el proyecto, compilarlo y ejecutar el código compilado.

    Nota:
    Abajo te dejo un ZIP con el código fuente del proyecto (Compilar y ejecutar) y la utilidad para colorear (gsColorearCore).
    En la carpeta pruebas del proyecto está el código fuente (de VB y C#) de la aplicación de ejemplo.

    Compilar con dotnet (desde la línea de comandos)

    En las primeras pruebas (las del código que te puse en el post arriba mencionado, usaba aplicaciones de consola, más que nada porque así se lo decía al usar el comando:

    dotnet new console -o "AppDir" -lang c#|vb

    Ese código lo que hace es crear una aplicación de consola en el directorio indicado por AppDir (si ya existe, podemos añadir –force al final para que genere el contenido aunque sobreesciba lo que ya hubiese.).

    Para crear/compilar una aplicación para Windows Forms tendremos que usar una línea de comandos parecida a la anterior, pero indicando winforms en vez de console.
    En el siguiente código creamos una aplicación de .NET 5.0 Core usando Visual Basic en el directorio E:\Guille\source\repos\MiAppWinF.

    Nota:
    Si no tienes instalado el .NET 5.0 y tienes al menos el .NET Core 3.0 o 3.1 simplemente usa el lenguaje C# en lugar de Visual Basic, ya que en esas versiones anteriores al 5.0 solo se permiten aplicaciones de Windows Forms o WPF para C#.

    dotnet new winforms -o "E:\Guille\source\repos\MiAppWinF" -lang vb

    Nota:
    En realidad poner el directorio entre comillas dobles no es necesario, salvo que se utilice el comando dotnet build.

    Una vez hecho esto, solo tendremos que modificar el código generado y si queremos que se ejecute el contenido de ese directorio podemos usa la siguiente línea de comandos:

    dotnet run -p E:\Guille\source\repos\MiAppWinF

    El código usado en la aplicación Compilar y ejecutar NETCore

    En el código de la aplicación compilar y ejecutar para .NET Core 5.0 este último paso me lo salto y lo que hago es crear la aplicación (con –force) sustituyo el código. ya que –force o simplemente al crear con new se generan los ficheros en blanco (sin el código que ya tuviera).
    En su lugar utilizo build para compilar el código.
    Es decir, creo la aplicación con new (uso –force por si ya existiera), guardo el código fuente del editor del programa, lo compilo con build y finalmente lo ejecuto usando Process.Start.

    El comando build usado es el siguiente:

    dotnet build "E:\Guille\source\repos\MiAppWinF"

    Las comillas dobles solo son necesarias si el path o el nombre del proyecto contiene espacios.

    Y ese comando habrá creado un ejecutable (aparte de la DLL que siempre genera .NET Core) en el directorio: E:\Guille\source\repos\MiAppWinF\bin\Debug\net5.0-windows cuyo nombre será MiAppWinF.exe
    Fíjate que al ser una aplicación para Windows (las aplicaciones de Windows Forms y las de WPF solo se pueden usar en plataformas Windows, es decir, no se pueden usar ni en Linux ni en MacOS) se crea en un directorio aparte de las aplicaciones de consola, que sería en: bin\Debug\net5.0\

    Nota:
    El directorio de salida puede ser diferente si antes de build (y después de new) cambias la configuración del proyecto.

    Un poco de código fuente por favor

    El código del método compilar al que se le pasa el código a compilar/ejecutar.

    ''' <summary>
    ''' Compilar el código indicado en el parámetro.
    ''' 
    ''' Usando dotnet (.NET Core) se hará lo siguiente:
    ''' Definir un directorio para VB o C#: MiApp_VB o MiApp_CS
    ''' Usar el comando:
    ''' dotnet new console -o dir -lang C#|VB --force
    ''' Copiar en ese directorio el fichero como Program.vb o .cs
    ''' Usar el comando (y redirigir la salida):
    ''' dotnet run -p dir
    ''' </summary>
    Private Sub compilar(texto As String, mostrarSoloSalida As Boolean)
        ' Compilar usando la línea de comandos
        Dim ext = If(optCS.IsChecked, "cs", "vb")
    
        Dim appDir = System.IO.Path.Combine(System.Environment.CurrentDirectory,
                                            $"MiApp_{ext}")
    
        ' crear un fichero temporal para compilar
        Dim ficProgram = Path.Combine(appDir, $"Program.{ext}")
    
        Dim dotnet = "dotnet"
        Dim args = "--version"
        txtSalida.Text = $"{dotnet} {args} = {ejecutar(dotnet, args, waitSecs:=5000)}"
    
        ' Considero que es aplicación de Windows Forms              (07/Sep/20)
        ' si contiene InitializeComponent
        Dim esWF = texto.IndexOf("InitializeComponent()") > -1
        If esWF Then
            args = $"new winforms -o ""{appDir}"" -lang {If(optCS.IsChecked, "c#", "vb")} --force"
        Else
            args = $"new console -o ""{appDir}"" -lang {If(optCS.IsChecked, "c#", "vb")} --force"
        End If
    
        If mostrarSoloSalida Then
            ejecutar(dotnet, args, waitSecs:=10000)
        Else
            txtSalida.Text &= $"{vbCrLf}{vbCrLf}{ejecutar(dotnet, args, waitSecs:=10000)}"
        End If
    
        ' Eliminar todos los ficheros del lenguaje
        ' (solo quedará el que se guarde)
        Dim files = Directory.GetFiles(appDir, $"*.{ext}")
        For i = 0 To files.Length - 1
            File.Delete(files(i))
        Next
    
        ' Guardar el código a compilar
        Using sw As New System.IO.StreamWriter(ficProgram,
                                               False,
                                               System.Text.Encoding.UTF8)
            sw.Write(texto)
        End Using
    
        args = $"build ""{appDir}"""
    
        If mostrarSoloSalida Then
            Dim res = ejecutar(dotnet, args, waitSecs:=10000)
            Dim hayErrorComp = False
            If optVB.IsChecked Then
                If res.Contains("error BC") Then
                    hayErrorComp = True
                End If
            Else
                If res.Contains("error CS") Then
                    hayErrorComp = True
                End If
            End If
            If hayErrorComp Then
                txtSalida.Text &= vbCrLf & res
                txtSalida.Text &= $"{vbCrLf}--- FIN DE LA COMPILACIÓN CON ERRORES ---"
                Return
            End If
            'txtSalida.Text &= $"{vbCrLf}{vbCrLf}{res}"
        Else
            txtSalida.Text &= $"{vbCrLf}{vbCrLf}{ejecutar(dotnet, args, waitSecs:=10000)}"
        End If
    
        Dim exe = System.IO.Path.Combine(appDir, $"bin\Debug\net5.0\MiApp_{ext}.exe")
        ' Si es aplicación de Windows Forms, usa otro directorio    (07/Sep/20)
        If esWF Then
            'net5.0-windows
            exe = System.IO.Path.Combine(appDir, $"bin\Debug\net5.0-windows\MiApp_{ext}.exe")
            txtSalida.Text &= $"{vbCrLf}{vbCrLf}Aplicación de Windows"
        End If
        txtSalida.Text &= $"{vbCrLf}{vbCrLf}{ejecutar(exe, esWinF:=esWF)}"
    
        txtSalida.Text &= $"{vbCrLf}--- FIN DE LA COMPILACIÓN ---"
    
        txtSalida.SelectionStart = txtSalida.Text.Length
        txtSalida.SelectionLength = 0
    End Sub
    

    Del método ejecutar tengo dos versiones, la primera es la que uso para llamar al dotnet y en el que redirijo la salida de la consola para capturarla y mostrarla en la caja de textos txtSalida.
    Al primero le paso el nombre de la aplicación a ejecutar (dotnet) y los argumentos.
    Al segundo le paso el nombre del ejecutable y si es o no aplicación de Windows, en cuyo caso se usa ShellExecute y el estilo de la ventana es normal, aparte de no usar Kill para que no se cierre la aplicación al poco de haberse abierto 🙂

    Private Function ejecutar(exe As String, arg As String,
                              Optional conKill As Boolean = False,
                              Optional waitSecs As Integer = 10000) As String
        Dim res = ""
        Using p As New Process
            p.StartInfo.FileName = exe
            p.StartInfo.Arguments = arg
    
            ' Indicamos que queremos redirigir la salida
            p.StartInfo.RedirectStandardOutput = True
            ' Para redirigir la salida, UseShellExecute debe ser falso
            p.StartInfo.UseShellExecute = False
    
            p.StartInfo.CreateNoWindow = True
    
            Try
                ' Iniciamos el proceso
                p.Start()
    
                ' Esperar a que el proceso finalice
                '
                ' Esperamos waitSecs segundos para que le de tiempo a ejecutarse
                ' como mínimo esperar 2000 (o 5000 si se usa dotnet)
                If waitSecs < 2000 Then waitSecs = 2000
                p.WaitForExit(waitSecs)
    
                If conKill Then
                    p.Kill()
                End If
    
                res = p.StandardOutput.ReadToEnd()
            Catch ex As Exception
    
                res = ex.Message
            End Try
        End Using
    
        Return res
    End Function
    
    ''' <summary>
    ''' Ejecutar el código y mostrarlo en la ventana de salida.
    ''' </summary>
    Private Function ejecutar(exe As String,
                              Optional waitSecs As Integer = 2000,
                              Optional esWinF As Boolean = False) As String
        Dim p As New Process
    
        p.StartInfo.FileName = exe
    
        If esWinF Then
    
            With p.StartInfo
                .UseShellExecute = True
                .WindowStyle = ProcessWindowStyle.Normal
            End With
    
            ' Iniciamos el proceso
            p.Start()
    
            ' Esperar a que el proceso finalice
            '
            ' Esperamos 2 segundos para que le de tiempo a ejecutarse
            ' Como mínimo 2 segundos
            If waitSecs < 2000 Then waitSecs = 2000
            p.WaitForExit(waitSecs)
    
            Return ""
        End If
    
        ' Indicamos que queremos redirigir la salida
        p.StartInfo.RedirectStandardOutput = True
        ' Para redirigir la salida, UseShellExecute debe ser falso
        p.StartInfo.UseShellExecute = False
    
        ' No usar esto
        ' salvo que se use p.Kill()
        p.StartInfo.CreateNoWindow = True
    
        ' Iniciamos el proceso
        p.Start()
    
        ' Esperar a que el proceso finalice
        '
        ' Esperamos 2 segundos para que le de tiempo a ejecutarse
        ' Como mínimo 2 segundos
        If waitSecs < 2000 Then waitSecs = 2000
        p.WaitForExit(waitSecs)
        Try
            p.Kill()
        Catch ex As Exception
            Debug.WriteLine(ex.Message)
        End Try
    
        ' Convertir la salida usando el código de página 437
        ' que es la usada en MS-DOS (línea de comandos)
        Dim res = p.StandardOutput.ReadToEnd()
    
        Return res
    End Function
    

    Recomendación para usar código de Windows Forms en la utilidad de Compilar y ejecutar

    Por último, comentarte que si quieres compilar una app para Windows Forms desde la utilidad de compilar y ejecutar, el código de esa aplicación debe estar en un solo fichero, en el que te recomiendo que incluyas el método Main, la definición del diseñador de Windows Forms y el código que realmente quieres usar.
    Esto es así porque el programa/utilidad no está preparado para usar múltiples ficheros.

    Te muestro a continuación cómo sería ese código para Visual Basic y para C# y una captura de la salida realizada al compilar desde la utilidad.

    Este es el código de Visual Basic del formulario de pruebas.

    Imports System
    Imports System.Windows.Forms
    
    '
    ' El punto de entrada del programa
    '
    
    Friend Module Program
    
        <STAThread()>
        Friend Sub Main(args As String())
            Application.SetHighDpiMode(HighDpiMode.SystemAware)
            Application.EnableVisualStyles()
            Application.SetCompatibleTextRenderingDefault(False)
            Application.Run(New Form1)
        End Sub
    
    End Module
    
    '
    ' El diseñador del formulario
    '
    
    <Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
    Partial Class Form1
        Inherits System.Windows.Forms.Form
    
        'Form overrides dispose to clean up the component list.
        <System.Diagnostics.DebuggerNonUserCode()> _
        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            Try
                If disposing AndAlso components IsNot Nothing Then
                    components.Dispose()
                End If
            Finally
                MyBase.Dispose(disposing)
            End Try
        End Sub
    
        'Required by the Windows Form Designer
        Private components As System.ComponentModel.IContainer
    
        'NOTE: The following procedure is required by the Windows Form Designer
        'It can be modified using the Windows Form Designer.  
        'Do not modify it using the code editor.
        <System.Diagnostics.DebuggerStepThrough()> _
        Private Sub InitializeComponent()
            Me.TextBox1 = New System.Windows.Forms.TextBox()
            Me.Button1 = New System.Windows.Forms.Button()
            Me.Label1 = New System.Windows.Forms.Label()
            Me.Button2 = New System.Windows.Forms.Button()
            Me.SuspendLayout()
            '
            'TextBox1
            '
            Me.TextBox1.Location = New System.Drawing.Point(12, 12)
            Me.TextBox1.Name = "TextBox1"
            Me.TextBox1.Size = New System.Drawing.Size(182, 23)
            Me.TextBox1.TabIndex = 0
            '
            'Button1
            '
            Me.Button1.Location = New System.Drawing.Point(200, 11)
            Me.Button1.Name = "Button1"
            Me.Button1.Size = New System.Drawing.Size(75, 23)
            Me.Button1.TabIndex = 1
            Me.Button1.Text = "Button1"
            Me.Button1.UseVisualStyleBackColor = True
            '
            'Label1
            '
            Me.Label1.Location = New System.Drawing.Point(12, 38)
            Me.Label1.Name = "Label1"
            Me.Label1.Size = New System.Drawing.Size(263, 23)
            Me.Label1.TabIndex = 2
            Me.Label1.Text = "Label1"
            '
            'Button2
            '
            Me.Button2.Location = New System.Drawing.Point(200, 90)
            Me.Button2.Name = "Button2"
            Me.Button2.Size = New System.Drawing.Size(75, 23)
            Me.Button2.TabIndex = 3
            Me.Button2.Text = "Cerrar"
            Me.Button2.UseVisualStyleBackColor = True
            '
            'Form1
            '
            Me.AcceptButton = Me.Button1
            Me.AutoScaleDimensions = New System.Drawing.SizeF(7.0!, 15.0!)
            Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
            Me.CancelButton = Me.Button2
            Me.ClientSize = New System.Drawing.Size(287, 125)
            Me.Controls.Add(Me.Button2)
            Me.Controls.Add(Me.Label1)
            Me.Controls.Add(Me.Button1)
            Me.Controls.Add(Me.TextBox1)
            Me.Name = "Form1"
            Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
            Me.Text = "Form1"
            Me.ResumeLayout(False)
            Me.PerformLayout()
    
        End Sub
    
        Friend WithEvents TextBox1 As TextBox
        Friend WithEvents Button1 As Button
        Friend Label1 As Label
        Friend Button2 As Button
    End Class
    
    '
    ' El código del formulario
    '
    
    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            TextBox1.Text = "<tu nombre>"
    
            'AddHandler Button2.Click, AddressOf Button2_Click
            AddHandler Button2.Click, Sub() Me.Close()
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim str = TextBox1.Text
            If str = "<tu nombre>" Then
                str = " amigo"
            End If
            Label1.Text = $"¡Hola {ToUpperFirst(str)}!"
        End Sub
    
        ''' <summary>
        ''' Convierte en mayúsculas el primer carácter de la cadena indicada.
        ''' </summary>
        Private Function ToUpperFirst(str As String) As String
            'Return str(0).ToString().ToUpper() & str.Substring(1)
            if str="" then str=" amigo"
            Return str(0).ToString.ToUpper & str.Substring(1)
        End Function
    
        'Private Sub Button2_Click(sender As Object, e As EventArgs)
        '    Me.Close()
        'End Sub
    End Class
    

    Este es el código de C# del formulario de pruebas.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    
    //
    // El punto de entrada del programa
    //
    
    static class Program
    {
        /// <summary>
        ///  The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.SetHighDpiMode(HighDpiMode.SystemAware);
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
    
    
    //
    // El diseñador del formulario
    //
    
    partial class Form1
    {
        /// <summary>
        ///  Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
    
        /// <summary>
        ///  Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
    
        #region Windows Form Designer generated code
    
        /// <summary>
        ///  Required method for Designer support - do not modify
        ///  the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.button1 = new System.Windows.Forms.Button();
            this.label1 = new System.Windows.Forms.Label();
            this.button2 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // textBox1
            // 
            this.textBox1.Location = new System.Drawing.Point(12, 12);
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(182, 23);
            this.textBox1.TabIndex = 0;
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(200, 12);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(75, 23);
            this.button1.TabIndex = 1;
            this.button1.Text = "button1";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // label1
            // 
            this.label1.Location = new System.Drawing.Point(12, 38);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(263, 23);
            this.label1.TabIndex = 2;
            this.label1.Text = "label1";
            // 
            // button2
            // 
            this.button2.Location = new System.Drawing.Point(200, 90);
            this.button2.Name = "button2";
            this.button2.Size = new System.Drawing.Size(75, 23);
            this.button2.TabIndex = 3;
            this.button2.Text = "Cerrar";
            this.button2.UseVisualStyleBackColor = true;
            //this.button2.Click += new System.EventHandler(this.button1_Click);
            // 
            // Form1
            // 
            this.AcceptButton = this.button1;
            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.CancelButton = this.button2;
            this.ClientSize = new System.Drawing.Size(287, 125);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.button1);
            this.Controls.Add(this.textBox1);
            this.Controls.Add(this.button2);
            this.Name = "Form1";
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);
            this.PerformLayout();
    
        }
    
        #endregion
    
        private System.Windows.Forms.TextBox textBox1;
        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Button button2;
    }
    
    //
    // El código del formulario
    //
    
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    
        private void Form1_Load(object sender, EventArgs e)
        {
            textBox1.Text = "<tu nombre>";
            
            //button2.Click += => (object o, EventArgs e) this.Close();
            //button2.Click += delegate (object sender, EventArgs e) { this.Close(); };
            button2.Click += (sender, e) => { this.Close(); };
        }
    
        private void button1_Click(object sender, EventArgs e)
        {
            //label1.Text = $"Hola {ToUpperFirst(textBox1.Text)}!";
            var str = textBox1.Text;
            if( str == "<tu nombre>" ) str = " amigo";
            label1.Text = $"Hola {ToUpperFirst(str)}!";
        }
    
        /// <summary>
        /// Convierte en mayúsculas el primer carácter de la cadena indicada.
        /// </summary>
        private string ToUpperFirst(string str)
        {
            if(str=="") str = " amigo";
            return str[0].ToString().ToUpper() + str.Substring(1);
        }
    }
    

    Esta es la salida del código ejecutándose con la utilidad de compilar y ejecutar para NETCore.

    Figura 1. El resultado de compilar y ejecutar una aplicación de Windows Forms para .NET Core 5.0.

    Y esto es todo… tengo algo más por ahí, para seguir con la compilación y ejecución del código para .NET Core, pero eso será para otra ocasión 🙂

     

    Espero que te haya sido de utilidad… Esa es la idea y ¡eso espero! 🙂

     

    Nos vemos.
    Guillermo

    El ZIP con el código fuente:

    ZIP: Compilar_ejecutar_NetCore_20200908_1551.zip (71.8 KB)
    MD5 checksum: 52A9AD9A1F1605547D1C8451CADD4CF0

  • Compilar y ejecutar versión para .NET Core (.NET 5.0)

    Nota del 26-oct-2020:
    Esta utilidad (seguramente) no tendrá más actualizaciones.
    En su lugar he publicado otra más completa en github: gsEvaluarColorearCodigoNET que incluye evaluación del código, compilar, compilar y ejecutar (por ahora para un solo fichero), colorear y colorear en HTML y tiene cosas interesantes para la creación de un editor de múltiples ficheros con algunas utilidades más.
    Cuando tenga la página publicada en el blog, te dejaré el enlace.

     

    Pues eso… siguiendo las pruebas de crear proyectos de .NET Core (con .NET 5.0) para Visual Basic, aquí traigo el de Compilar y Ejecutar que está creado con WPF / XAML y que además usa la biblioteca de clases para colorear (gsColorearCore) que también he convertido para .NET Core, en esta ocasión para la versión 3.1.

    La he convertido para usar con .NET 5.0 (.NET Core), más que nada para probar, pero visto lo visto (los problemas) prefiero quedarme con la versión de .NET Framework.

    Nota:
    Abajo tienes una actualización del 16/Sep/2020

     

    ¿Por qué es preferible usar .NET Framework para este tipo de aplicación?

    Por la sencilla razón de que salvo cosas puntuales, no tiene mucho sentido hacerla para .NET Core. Ya que este tipo de aplicaciones (las creadas para WPF o Windows Forms) solo se ejecutarán o funcionarán en equipos que utilicen Windows como sistema operativo.

    Que tú prefieres usar el .NET Core porque «DICEN» que es más rápido, ocupa menos, se puede «embeber» con la aplicación y otras monerías… pues muy bien… lo mismo yo utilizo esas cosas «puntuales» para hacer algo con .NET 5.0, o hacer mucho cuando ya sea .NET 6.0, el tiempo lo dirá… No hay que descartar nada ni decir de este agua no beberé 😉

    Cosas a tener en cuenta en la migración de .NET Framework a .NET Core

    Aparte de que hay ciertas cosas que ya no existen, al menos de la forma a la que estamos habituados en las aplicaciones para .NET Framework, el resto no cambia nada o no cambia mucho.

    Configuración (My.Settings)

    Por ejemplo, me he encontrado con problemas a la hora de usar My.Settings. Me estuvo funcionando y de buenas a primeras dejó de hacerlo, así que… corté por lo sano y me deshice de My.Settings y las configuración la uso por mi cuenta, concretamente usando la clase Config que tengo definida en la DLL de gsColorear.

    No quiero decir con esto que no se puedan usar… solo digo que a mí me estuvo funcionando bien hasta que de buenas a primeras dejó de funcionar.

    Propiedades del proyecto

    A las propiedades del proyecto ya no accede desde el nodo MyProject.
    Ahora puedes hacerlo pulsando en el nombre del proyecto con el botón secundario del ratón (normalmente el derecho) y del menú mostrado pulsar en Propiedades (ver la figura 1).

    Figura 1. Acceder a las propiedades del proyecto

    NOTA:
    Si simplemente haces clic en el nombre del proyecto (y la ventana de propiedades no estaba abierta anteriormente y ocasionalmente si también está abierta) se mostrará el fichero .vbproj con las opciones de configuración en formato XML no con tantas «cosas» como el de una aplicación para .NET Framework (ver la figura 2).
    Ahí, entre otras cosas, se indica la versión del .NET Core que estás usando (en este caso .NET 5.0 para Windows), qué tipo de aplicación es, el espacio de nombres, etc.

    Figura 2. Propiedades del proyecto en XML

    Este es el aspecto (simplificado) de la ventana de propiedades del proyecto (ver figura 3).

    Figura 3. Ventana de propiedades del proyecto

    Si pulsas en Paquete (en el panel izquierdo de la ventana de Propiedades) tendrás algo parecido a la información del ensamblado de las aplicaciones para .NET Framework.

    Referencias

    Las referencias a DLL externas (u otros proyectos), se pueden hacer desde la ventana de propiedades, pero en la ventana del explorador de soluciones ya no se muestra como el nodo Referencias. Ahora está en Dependencias.

    Si pulsas en Referencias de la ventana de propiedades, verás que está vacía, pero puedes agregar las referencias que necesites, supongo que, a diferencia de una aplicación de .NET Framework, aquí solo tienes que añadir las referencias externas, es decir, las que no se encuentren ya definidas en el propio .NET Core.

    En realidad en Dependencias añadirás las mismas cosas que antes (con .NET Framework) añadías en tu proyecto: paquetes NuGet, referencias a otros proyectos, etc.

    En el caso de las referencias a otros proyecto, están en un nodo diferenciado (Proyectos), tal como puedes comprobar en la figura 4.

    Figura 4. Nodo de proyectos usados en el proyecto actual

    Y básicamente estos es lo diferente… y eso que no me he puesto a añadir configuraciones ni recursos desde la ventana de propiedades… pero eso lo dejo estar… al menos por ahora 😉

     

    Todo esto lo estoy escribiendo el 5 de septiembre de 2020 y estoy usando Visual Studio Community 2019 Preview Versión 16.8.0 Preview 2.1 con el .NET 5.0 versión 5.0.100-preview.8.20417.9.

    Para estas pruebas he copiado el proyecto para WPF Compilar y ejecutar versión 1.0.0.21 del 31 de agosto de 2020 con la librería gsColorear2008 versión 1.0.6.3 del 8 de enero de 2019.

    Nota:
    Me apunto actualizar la página de gsColorear en mi sitio para que tenga la última versión tanto de la DLL como de la aplicación.

    En la librería de colorear el código, también tuve que quitar los ficheros de recursos (con las palabras clave de los lenguajes) y guardarlos (y abrirlos al usarlos) de forma manual en vez de como si fuese un recurso. No fue complicado, pero… es otra cosa que rompe la compatibilidad entre proyectos. Y esto es independiente de la versión de .NET Core que tenga asignada en el proyecto, ya que lo probé inicialmente con el .NET 5.0 y después con el .NET Core 3.1.
    Al final lo he dejado con el .NET Core 3.1, ya que al ser una biblioteca de clases, .NET Core 3.1 si da soporte a ese tipo de proyectos de Visual Basic.

     

    Y esto es todo por hoy… otro día más…

    Espero que te haya sido de utilidad.

     

    Actualización del 16/Sep/2020

    He actualizado el código, tanto de la utilidad de compilar y ejecutar como de la DLL de compilar, esta última ahora usa código de Visual Basic en lugar de C#, y también he actualizado la DLL de colorear el código.

    Todos esos cambios están en el repositorio de gitHub de gsCompilarEjecutarNET.

    Además, he convertido el código de la utilidad a C# y también está publicado en gitHub.

     

    Aquí te dejo el enlace original al código que puse cuando publiqué este artículo originalmente el 5 de septiembre.

    El enlace para descargar los proyectos Compilar y ejecutar y gsColorearCore para .NET Core

    ZIP: Compilar_ejecutar_NetCore_20200905_1710.zip (70.8 KB)
    MD5 checksum: ACDC9EF7E2C0F4469719F06D88F8F812

     

    Nos vemos.
    Guillermo

  • Tips para crear proyectos de .NET Core (.NET 5.0) en Visual Studio 2019 Preview

    Pues eso… leyendo el otro día el artículo Visual Basic support planned for .NET 5.0 (soporte planeado en .NET 5.0 para Visual Basic) indicaba una serie de tipos de proyectos, entre ellos de Windows Forms y WPF, pero no solo para Windows y usando el .NET Framework (que es lo que dicen por ahí que será lo que nos quede en un futuro a los que preferimos usar Visual Basic en lugar de C# (u otro lenguaje de .NET).

    Así que… abrí el Visual Studio 2019 (Community) Preview (v16.8.0 Preview 2) y me puse a mirar los tipos de proyectos que había… para C# había de esos dos tipos de aplicaciones tanto para .NET Core como para .NET Framework, pero para Visual Basic solo era para este último marco de trabajo.

    Mirando la configuración de los ficheros del proyecto de C# pude crear un proyecto de Windows Forms para Visual Basic que usa el .NET 5.0 basándome en uno de consola (de esos si que hay para el .NET Core o el .NET 5.0).

    ¡Y funciona!

    El problema, es que al agregar los controles al formulario y crear los métodos de evento (haciendo doble-pulsación en el control), los métodos de evento se creaban, pero no estaban conectados con los controles. Y eso es porque al crear los controles (añadiéndolos al formulario) no se definían con WithEvents.

    La solución es fácil, se abre el fichero Form1.Designer.vb, se modifica la declaración de los controles (que suelen estar al final de ese fichero) y asunto arreglado… bueno, si le añades el típico Handles después de la declaración del método, por ejemplo:

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Label1.Text = "¡Hola Mundo!"
    End Sub
    

    Esto último es lo menos engorroso de hacer… lo complicado (o tedioso) es convertir ese proyecto de consola a uno de Windows Forms.
    ¡Y no te voy a explicar cómo hacerlo! 🙂
    No, ya que no es necesario hacer nada si sigues el consejo que te daré a continuación.

    Crear proyectos de Visual Basic para .NET Core (o .NET 5.0)

    Si no quieres complicarte mucho la vida, haz lo siguiente (tal como se muestra en la figura 1):

    Selecciona el menú de Herramientas>Opciones y se muestra la ventana de configuración, selecciona Entorno>Características en versión preliminar y ahí marca la casilla Mostrar todas las plantillas de .NET Core en el cuadro de diálogo nuevo proyecto y pulsa Aceptar. Tendrás que cerrar y abrir nuevamente el Visual Studio y ya tendrás todas las plantillas que hay actualmente disponibles.

     

    Usar los nuevos tipos de proyectos

    Si ahora creas un nuevo proyecto (o agregas uno a una solución existente) verás que ya están los proyectos de Visual Basic para todas las plataformas (usando Windows Forms y WPF entre otros).

    Una vez que seleccionas uno de los proyectos para «todas las plataformas» te dará la opción de elegir la plataforma de destino (el «framework» que usarás). (ver la figura 3)

    Si eliges una aplicación de WPF te mostrará las 3 opciones de la figura anterior, si eliges una aplicación de Windows Forms, solo mostrará .NET Core 3.1 y .NET 5.0.

     

    NOTA:
    Como sabrás .NET 5.0 es una especie de remix entre el .NET Framework y el .NET Core o lo que es lo mismo, es la continuidad de .NET Core, pero unificado con el .NET Framework.
    Y la primera versión definitiva está planeada para noviembre de este año de 2020.

     

    ¿Se soluciona algo al crear así las aplicaciones de Windows Forms?

    Pues no… o casi… Me refiero a que al añadir un control al formulario y hacer doble-clic en él se genere correctamente el método de evento.

    Ni usando el .NET Core 3.1 ni usando el .NET 5.0 (al menos en Visual Basic) se generan correctamente esos métodos de evento.

    Si usas .NET Core 3.1 como plataforma de destino, al menos se definirán los controles con WithEvents, pero tendrás que añadirle el Handles o enlazar el evento y el método con AddHandler.

    Si usas como plataforma de destino el .NET 5.0, no se definen los controles con WithEvents y, por tanto, tampoco se crean los métodos con Handles ya que es un requisito el que las variables (controles en este caso) estén definidos con WithEvents para permitir definir los eventos con Handles.

     

    A esperar toca…

    Esperemos que en futuras revisiones del .NET 5.0 o de Visual Studio esté solucionado, si no… lo tenemos complicado.
    No sé quién será el encargado de arreglar esto, supongo que los de VS, y esperemos que sea así, ya que el .NET 5.0 ha entrado en lo que llaman la fase “feature complete” (función completa) en la Preview 8 de hace una semana y ya solo nos quedan las release candidate en las que solo arreglan bugs, no añaden nuevas características.

    Habrá que reportarlo como BUG para ver si hacen algo y lo solucionan… porque si no lo solucionan, es que realmente no quieren que los desarrolladores de Visual Basic sigamos usándolo… y… optemos por cambiar a C#… en fin…

     

    Nota:
    Aunque al crear los proyectos de Windows Forms y WPF aparentemente sean para todas las plataformas, en realidad solo están soportadas en Windows.
    O al menos eso quiere decir (o es lo que yo entiendo que significa) esto en la configuración de la aplicación:

    <TargetFramework>net5.0-windows</TargetFramework>
    

     

    Espero que te haya servido para algo todo lo aquí comentado… ya sabes que esa es la idea 😉

    Nos vemos.
    Guillermo