Autor: elGuille

  • Compilar y ejecutar

    Compilar y ejecutar es una utilidad creada con WPF (.NET 4.7.2) para compilar y ejecutar aplicaciones tipo consola desde la misma aplicación. Permite guardar el código de VB y C# así como la salida de la consola. Permite colorear el código (tanto de VB como el de C#) y tiene algunos trucos para redirigir la salida de un ejecutable, sincronizar el contenido de dos TextBox, añadir y recuperar texto (o el contenido) de un RichTextBox, y más…

    Para compilar utiliza Roslyn 2.0.1 (Microsoft.CodeDom.Providers.DotNetCompilerPlatform) de esta forma permite el uso de código para compilar con C# 7.3 y VB 15.5 ya que el compilador predeterminado de CodeDom es para las versiones 5 de C@ y 11 de Visual Basic. Por tanto, puedes usar Tuplas si quieres Winking smile

    En la figura 1 puedes ver la aplicación en ejecución con un código de Visual Basic coloreado, mostrando la salida de la aplicación (de consola).

    Figura 1. La aplicación en funcionamiento
    Figura 1. La aplicación en funcionamiento

    En la salida por la consola las vocales acentuadas (con tildes) no se mostraban bien y he usado un truco para convertir el texto de la consola de forma que se pueda leer sin problemas, concretamente usando la codificación de la página de códigos 437 usando GetEncoding(437).

    Este es el código (para VB) que hace la conversión de lo leído por la salida estándar de un objeto Process y convirtiéndolo en texto (un truco para convertir un MemoryStream en texto o cadena).

    ' Convertir la salida usando el código de página 437
    ' que es la usada en MS-DOS (línea de comandos)
    Dim texto = p.StandardOutput.ReadToEnd()
    Dim ms As New MemoryStream(ASCIIEncoding.[Default].GetBytes(texto))
    texto = Encoding.GetEncoding(437).GetString(ms.ToArray())
    

    En otra ocasión te explicaré con más detalle todas las cosillas que la aplicación hace, por ahora te dejo el zip con el código fuente de Visual Basic en una solución para Visual Studio 2017 además del ejecutable y si prefieres instalarla usando ClickOnce, también lo puedes hacer, más abajo tienes los enlaces.

    Comentarte que en el ZIP se incluye los packages de Roslyn.

    Y esto ews todo por ahora… Smile

    Espero que te sea de utilidad

    Nos vemos.
    Guillermo

    P.S (27-feb-2021 15:19)
    No sé porqué esto lo tenía como borrador… seguramente porque no estará completa la entrada, pero… así la dejo 😉

  • ¿Quieres aprender a programar usando .NET Core sin instalar nada?

    Pues eso… me he metido en la página de instalación del .NET Core 3.0 SDK y he visto un botón con el enlace «Get Started» (ver la figura 1) y me ha llevado a la página de .NET Tutorial – Hello World in 10 minutes y en la parte de la izquierda he visto un botón con el texto Try .NET in your browser (ver figura 2) y lo he pulsado… y me ha llevado a una página en la que te va explicando las cosas básicas para crear una aplicación de consola, empezando con el clásico «Hello World!» (ver figura 3) que después ha pasado al «Hello Guillermo!» (o tu nombre) y ha seguido haciendo cambios y enseñando algunas cosas, que al menos yo ya había leído, pero así lo he tenido más claro (ver figura 4)…. bueno, es curioso más que nada… y no acaba ahí la cosa (yo no he seguido) pero se ve que sigue con otras cosas como trabajar con números, aunque esta vez ha cambiado el formato, pero básicamente es en el mismo tono (ver figuras 5 y 6), así que… te lo recomiendo ya que las cosas que incluyen son:

    Análisis de las operaciones matemáticas con enteros
    Análisis sobre el orden de las operaciones
    Información sobre los límites y la precisión de los enteros
    Operaciones con el tipo double
    Operaciones con tipos de punto fijo

    Eso sí, todo con puntos y comas… Smile

    Las capturas

    Figura 1. Get Started en la página de descarga del .NET Core 3.0 SDK
    Figura 1. Get Started en la página de descarga del .NET Core 3.0 SDK

    Figura 1.

    Figura 2. El tutorial con el botón de Try .NET in your browser
    Figura 2. El tutorial con el botón de Try .NET in your browser

    Figura 2.

    Figura 3. El tutorial de .NET In-Browser
    Figura 3. El tutorial de .NET In-Browser

    Figura 3.

    Figura 4. String Interpolation
    Figura 4. String Interpolation

    Figura 4.

    Figura 5. Aquí acaba el tutorial .NET In-Browser
    Figura 5. Aquí acaba el tutorial .NET In-Browser

    Figura 5.

    Figura 6. El tutorial de C# sigue con el compilador In-Browser
    Figura 6. El tutorial de C# sigue con el compilador In-Browser

    Los enlaces:

    Espero que si no te es de utilidad al menos te relaje un poco… jajajaja

    Nos vemos.
    Guillermo

  • Recomendaciones para adaptar los controles (y la fuente) en aplicaciones WPF (2ª parte el código para C#)

    Pues eso… lo prometido es deuda… aquí tienes el código para C# de las Recomendaciones para adaptar los controles (y la fuente) en aplicaciones WPF.
    También te enseñaré el código XAML modificado o rectificado desde la última vez, es decir, desde que ayer publiqué el original Winking smile

    Esta es la ventana de la aplicación en modo diseño (figura 1).

    Figura 1. La ventana principal en modo diseño
    Figura 1. La ventana principal en modo diseño

    Los cambios en el código XAML que he puesto son menores, para que los botones de seleccionar de los paneles superiores no se peguen demasiado a las esquinas de la derecha, para ello he cambiado el valor de Padding del control GroupBox y he reducido el margen (Margin) de la parte izquierda de los botones. También he puesto el ancho de la primera columna del ListView a 220, ya que hay espacio suficiente (la ventana principal tiene asignado un valor mínimo de 830 de ancho.

    Por si te sirve de ayuda, sobre todo si has usado padding y margin en los estilos CSS.

    Comentarte que los valores de Padding y Margin en Xaml se refieren a las posiciones:
    left, top, right, bottom,
    a diferencia de las usadas en los estilos CSS, que hacen referencia a:
    top right bottom left.
    De nada Be right back

    Aquí tienes el código XAML (del diseñador de WPF) del panel superior izquierdo, el de la derecha es prácticamente igual.

    <GroupBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="1" 
              Header="Unidad 1" Margin="0" Padding="0,0,4,0">
        <Grid DockPanel.Dock="Top" Margin="0" >
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="30"/>
                <RowDefinition Height="4"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Label Content="Directorio:" Grid.ColumnSpan="1" Margin="0,4,0,0" />
            <TextBox Name="txtDir1" Grid.Row="0" Grid.Column="1" 
                     Grid.ColumnSpan="3" Grid.RowSpan="1"
                     Margin="0,6,0,0" KeyDown="txtDir1_KeyDown"
                     TextWrapping="NoWrap" Text="S:\iPhone"/>
            <Button Name="btnSel1" Content=" Seleccionar... " 
                    Grid.Column="4" Grid.ColumnSpan="1"
                    Margin="4,6,0,0" Click="BtnSel_Click" />
            <ListView Name="lvFics1" Grid.Row="2"
                      Grid.ColumnSpan="5" Grid.RowSpan="1" 
                      Margin="0,8,0,0">
                <ListView.View>
                    <GridView >
                        <GridViewColumn Header="Archivo" Width="220"
                                        DisplayMemberBinding="{Binding Nombre}"/>
                        <GridViewColumn Header="Fecha" Width="Auto"
                                        DisplayMemberBinding="{Binding Fecha}"/>
                    </GridView>
                </ListView.View>
            </ListView>
        </Grid>
    </GroupBox>
    

    El ListView (concretamente cada GridViewColumn) definen un enlace (Binding) a Nombre y Fecha, de esa forma podremos agregar a cada elemento del ListView un objeto definido por nosotros (ItemFic) con esas dos propiedades y se asignarán correctamente a cada una de las columnas del ListView.

    Esta es la definición de las clases ItemFic y ItemDir, esta última la usaré para mostrar el nombre del directorio del ListView definido en el panel inferior.

    El método llenar es el que se encarga de asignar los elementos a los ListView.

    class ItemDir
    {
        public string Nombre { get; set; }
    }
    
    class ItemFic : ItemDir
    {
        public DateTime Fecha { get; set; }
    }
    
    /// <summary>
    /// Llenar un listview con los ficheros del directorio
    /// </summary>
    private void llenar(ListView lvFiles, string dir)
    {
        lvFiles.Items.Clear();
        var dirI = new sio.DirectoryInfo(dir);
        if (dirI.Exists == false)
            return;
    
        foreach (var fi in dirI.GetFiles())
        {
            var lvi = new ItemFic() { Nombre = fi.Name, Fecha = fi.LastWriteTime };
            lvFiles.Items.Add(lvi);
        }
    }
    

    Nota:
    sio es un alias al espacio de nombres System.IO ya que Path también está definido en System.Windows.Shapes y así no tenemos conflictos de nombres, al menos si usas C#, ya que al crear un proyecto WPF se añade esa importación de espacios de nombres.

    Cambiar el tamaño de la ventana principal y las letras

    Para gestionar el cambio de tamaño de la ventana y las letras de cada control he añadido un par de menús a la aplicación.

    Recuerda que para que los tamaños de las letras (FontSize) se hagan medio-automáticamente, tal como lo hago en esta aplicación, deben tener el valor predeterminado de las fuentes, es decir, NO añadas ningún valor a las fuentes de los controles o de los contenedores, si no, no funcionará.

    Este es el código XAML de la definición de los menús.

    <Menu x:Name="menu" Grid.Row="0" Grid.Column="0" 
          Grid.ColumnSpan="2" 
          Height="24" Margin="0,0,0,4">
        <MenuItem x:Name="mnuCambiarFuente" 
                  Header="_Tamaño y Fuente">
            <MenuItem Header="Tamaño _Ventana">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <Label Content="Cambiar tamaño" 
                           ToolTip="Puedes usar un valor negativo para reducir" />
                    <TextBox x:Name="txtTamañoVentana" Text="0,2" 
                             Grid.Column="1" Width="40"
                             Margin="8,6,0,0"/>
                    <Button x:Name="btnAplicar" Content=" Aplicar " 
                            Click="BtnAplicarVentana_Click"
                            Grid.Column="2" Margin="8,6,0,0" />
                </Grid>
            </MenuItem>
            <MenuItem Header="Tamaño _Fuente">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <Label Content="Cambiar tamaño" 
                           ToolTip="Puedes usar un valor negativo para reducir" />
                    <TextBox x:Name="txtTamañoFuente" Text="1,0" 
                             Grid.Column="1" Width="40"
                             Margin="8,6,0,0"/>
                    <Button x:Name="btnAplicarFuente" Content=" Aplicar " 
                            Click="BtnAplicarFuente_Click"
                            Grid.Column="2" Margin="8,6,0,0" />
                </Grid>
            </MenuItem>
        </MenuItem>
    
     </Menu>
    

    Aquí tienes el código de C# para cambiar el tamaño de las fuentes, se suma o sustrae el valor que indiquemos (si este último es negativo), y en el tamaño de la ventana principal añadimos (o restamos) el porcentaje indicado.

    private double meHeight;
    private double meWidth;
    private double meFontSize;
    
    private void BtnAplicarVentana_Click(object sender, RoutedEventArgs e)
    {
        // Para cambiar el tamaño a partir del valor inicial
        if (meHeight == 0)
            meHeight = this.Height;
        if (meWidth == 0)
            meWidth = this.Width;
    
        double d = 0;
        double.TryParse(txtTamañoVentana.Text, out d);
        this.Height = nuevoTamaño(meHeight, d);
        this.Width = nuevoTamaño(meWidth, d);
    }
    
    private void BtnAplicarFuente_Click(object sender, RoutedEventArgs e)
    {
        if (meFontSize == 0)
            meFontSize = this.FontSize;
        double d = 0;
        double.TryParse(txtTamañoFuente.Text, out d);
        this.FontSize = meFontSize + d;
    }
    
    
    private double nuevoTamaño(double actual, double incremento)
    {
        return actual * incremento + actual;
    }
    

    Quitar el botón maximizar de la ventana usando API

    Para terminar, te mostraré el código para quitar el botón de maximizar la ventana, ya que WPF no tiene opciones para ocultar ese botón, salvo que cambiemos el tipo de ventana, pero en este caso yo la tengo definida asignando a la propiedad ResizeMode el valor CanResizeWithGrip. Por tanto, puedo maximizar, minimizar, cambiar el tamaño, etc.

    Pero siempre queda bien eso de que el usuario no pueda maximizar de golpe, si quiere la ventana más grande, que le cambie el tamaño poco a poco Winking smile

    // --------------------------------------------------------------------------
    // Código para quitar el botón de maximizar
    // Adaptado de la versión de C# publicada en:
    // https://stackoverrun.com/es/q/5101958
    // 
    [DllImport("user32.dll")]
    private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
    
    [DllImport("user32.dll")]
    private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
    
    private const int GWL_STYLE = -16;
    private const int WS_MAXIMIZEBOX = 0x10000;
    
    private void Window_SourceInitialized(object sender, EventArgs e)
    {
        var hwnd = new WindowInteropHelper((Window)sender).Handle;
        var value = GetWindowLong(hwnd, GWL_STYLE);
        SetWindowLong(hwnd, GWL_STYLE, (int)(value & ~WS_MAXIMIZEBOX));
    }
    

    Los eventos, SourceInitialized y otros, están definidos en el código Xaml de la aplicación.

    Height="500" Width="850"
    MinHeight="460" MinWidth="830"
    WindowStartupLocation="CenterScreen"
    ResizeMode="CanResizeWithGrip"
    
    SourceInitialized="Window_SourceInitialized"
    
    Loaded="MainWindow_Loaded">
    

    Y esto es todo lo que quería contarte usando los puntos y comas In love

    Te recomiendo que te leas lo escrito en la primera parte, ya que aunque el código mostrado es para Visual Basic, las explicaciones, particularmente para el código XAML, te van a servir, seguro Smile

    Y para que vayas a la otra página, allí está el enlace para descargar el zip con el código completo, tanto para Visual Basic como para C#.

    Nos vemos.
    Guillermo