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

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *