Saltar al contenido

WPF & MVVM – Diseño de IU Principal Moderno – Parte 1

Hola, continuemos con la serie de tutoriales de WPF y MVVM, En los videos anteriores hicimos este formulario de inicio de sesión con C-Sharp y SQL Server, así que antes que nada te recomiendo ver y descargar el proyecto anterior para realizar este tutorial. Bueno, ahora crearemos la interfaz de usuario de vista principal elegante y moderno, crearemos los botones clásicos de cerrar, maximizar y minimizar, que al pasar el mouse cambian el color de fondo y el color del ícono, crearemos botones del menú de navegación, que cuando pasa el mouse sobre el botón, cambia el color y muestra el borde lateral del mismo color que el ícono, y si se selecciona un botón este se activa y permanece resaltado hasta que se seleccione otro botón del menú. Por otro lado, también les mostraré cómo abrir las vistas secundarias en la ventana principal desde el menú de navegación, en cuanto a los íconos, para poder cambiar el color, usaremos los íconos de Font Awesome, para ello descargue el paquete FontAwesome.Sharp desde Nuget. Bueno, Haremos todo ello implementando y respetando los principios del patrón MVVM y manteniendo la funcionalidad de una ventana estándar, como arrastrar la ventana, la función Aero Snap Windows, maximizar, restaurar, minimizar y cerrar.

Tutorial

Código

Diccionario de recursos

Lista de colores

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <!--Background Colors-->
    <Color x:Key="primaryBackColor1">#0A003A</Color>
    <Color x:Key="primaryBackColor2">#1C0E49</Color>
    <Color x:Key="secondaryBackColor1">#24105F</Color>
    <Color x:Key="secondaryBackColor2">#210F55</Color>

    <!--Window Border Colors-->
    <Color x:Key="winBorderColor1">#6D2FFF</Color>
    <Color x:Key="winBorderColor2">#FB539B</Color>
    <Color x:Key="winBorderColor3">#836EFB</Color>

    <!--Color Palette-->
    <SolidColorBrush x:Key="color1" Color="#E285DE"/>
    <SolidColorBrush x:Key="color2" Color="#784DFD"/>
    <SolidColorBrush x:Key="color3" Color="#4ADAEC"/>
    <SolidColorBrush x:Key="color4" Color="#FB539B"/>
    <SolidColorBrush x:Key="color5" Color="#7E82FC"/>
    <SolidColorBrush x:Key="color6" Color="#FFC047"/>
    <SolidColorBrush x:Key="color7" Color="#EF6C96"/>
    <SolidColorBrush x:Key="color8" Color="#78A3FC"/>
    <SolidColorBrush x:Key="color9" Color="#07F3C0"/>
    <SolidColorBrush x:Key="color10" Color="#FBA1AA"/>

    <!--Font Colors-->
    <SolidColorBrush x:Key="titleColor1" Color="#E0E1F1"/>
    <SolidColorBrush x:Key="titleColor2" Color="#D5CFF5"/>
    <SolidColorBrush x:Key="titleColor3" Color="#BCBEE0"/>
    <SolidColorBrush x:Key="plainTextColor1" Color="#9497CD"/>
    <SolidColorBrush x:Key="plainTextColor2" Color="#7C80C2"/>
    <SolidColorBrush x:Key="plainTextColor3" Color="#7376BD"/>

    <!--Panel Colors-->
    <SolidColorBrush x:Key="panelColor" Color="#200F53"/>
    <SolidColorBrush x:Key="panelOverColor" Color="#281269"/>
    <SolidColorBrush x:Key="panelActiveColor" Color="#2B1372"/>

    <!--Button Colors-->
    <!--TextBox Colors-->
    <!--Etc-->

</ResourceDictionary>

Estilos de botones

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:fa="http://schemas.awesome.incremented/wpf/xaml/fontawesome.sharp">

    <!--Menu button-->
    <Style x:Key="menuButton" TargetType="RadioButton">
        <!--Normal button style-->
        <Setter Property="Height" Value="50"/>
        <Setter Property="Margin" Value="-5,0,0,5"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="Foreground" Value="{StaticResource plainTextColor3}"/>
        <Setter Property="BorderBrush" Value="Transparent"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="RadioButton">
                    <Border Background="{TemplateBinding Background}"
                            BorderThickness="4,0,0,0"
                            BorderBrush="{TemplateBinding BorderBrush}">
                        <ContentPresenter HorizontalAlignment="Left" VerticalAlignment="Center"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>

        <Style.Triggers>
            <!--Button Style on hover-->
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Margin" Value="0,0,0,5"/>
                <Setter Property="Background" Value="{StaticResource panelOverColor}"/>
                <Setter Property="Foreground" Value="{StaticResource titleColor3}"/>
                <Setter Property="BorderBrush" Value="{Binding Path=Tag, RelativeSource={RelativeSource Self}}"/>
            </Trigger>

            <!--Activated button style-->
            <Trigger Property="IsChecked" Value="True">
                <Setter Property="Margin" Value="0,0,0,5"/>
                <Setter Property="Background" Value="{StaticResource panelActiveColor}"/>
                <Setter Property="Foreground" Value="{Binding Path=Tag, RelativeSource={RelativeSource Self}}"/>
                <Setter Property="BorderBrush" Value="{Binding Path=Tag, RelativeSource={RelativeSource Self}}"/>
            </Trigger>
        </Style.Triggers>
    </Style>
    
    <!--Menu button icon-->
    <Style x:Key="menuButtonIcon" TargetType="fa:IconImage">
        <Setter Property="Foreground" Value="{Binding Path=Tag, RelativeSource={RelativeSource AncestorType=RadioButton}}"/>
        <Setter Property="Width" Value="22"/>
        <Setter Property="Height" Value="22"/>
        <Setter Property="Margin" Value="35,0,20,0"/>
    </Style>
    
    <!--Menu button text-->
    <Style x:Key="menuButtonText" TargetType="TextBlock">
        <Setter Property="Foreground" Value="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=RadioButton}}"/>
        <Setter Property="FontFamily" Value="Montserrat"/>
        <Setter Property="FontWeight" Value="Medium"/>
        <Setter Property="FontSize" Value="13.5"/>
        <Setter Property="VerticalAlignment" Value="Center"/>
    </Style>

Archivo de la aplicación – App.XAML

<Application x:Class="WPF_LoginForm.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WPF_LoginForm"
             Startup="ApplicationStart">
    
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Styles/UIColors.xaml"/>
                <ResourceDictionary Source="/Styles/ButtonStyles.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
    
</Application>

Diseño de la vista principal

<Window x:Class="WPF_LoginForm.Views.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPF_LoginForm.Views"
        xmlns:viewModel="clr-namespace:WPF_LoginForm.ViewModels"
        xmlns:fa="http://schemas.awesome.incremented/wpf/xaml/fontawesome.sharp"
        mc:Ignorable="d"
        Title="MainWindowView" Height="700" Width="1300"
        WindowStartupLocation="CenterScreen"
        WindowStyle="None"
        Background="Transparent"
        AllowsTransparency="True">

    <Window.DataContext>
        <viewModel:MainViewModel/>
    </Window.DataContext>

    <Border CornerRadius="10"                    
            BorderThickness="1">

        <Border.BorderBrush>
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                <GradientStop Color="{StaticResource winBorderColor1}" Offset="0"/>
                <GradientStop Color="{StaticResource winBorderColor2}" Offset="0.5"/>
                <GradientStop Color="{StaticResource winBorderColor3}" Offset="1"/>
            </LinearGradientBrush>
        </Border.BorderBrush>

        <Grid>

            <Grid.ColumnDefinitions>
                <!--Navigation menu-->
                <ColumnDefinition Width="250"/>
                <!--Content section-->
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <!--Navigation Menu-->
            <Border CornerRadius="10,0,0,10"
                    Grid.Column="0">

                <Border.Background>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="1,0.7">
                        <GradientStop Color="{StaticResource secondaryBackColor1}" Offset="0"/>
                        <GradientStop Color="{StaticResource secondaryBackColor2}" Offset="1"/>
                    </LinearGradientBrush>
                </Border.Background>

                <StackPanel>
                    
                    <!--Logo-->
                    <StackPanel Orientation="Horizontal"
                                Height="35"
                                Margin="15,25,0,40">
                        
                        <Image Source="/Images/Logo.png" Height="30"/>
                        <TextBlock Text="RJ CODE"
                                   Foreground="{StaticResource titleColor2}"
                                   FontSize="20"
                                   FontFamily="Montserrat"
                                   FontWeight="Medium"
                                   VerticalAlignment="Center"
                                   Margin="10,0,0,0"/>

                    </StackPanel>
                    
                    <!--Menu Buttons-->
                    <RadioButton Style="{StaticResource menuButton}"
                                 Tag="{StaticResource color1}"
                                 IsChecked="True"
                                 Command="{Binding ShowHomeViewCommand}">
                        <StackPanel Orientation="Horizontal">
                            <fa:IconImage Icon="Home" Style="{StaticResource menuButtonIcon}"/>
                            <TextBlock Text="Dashboard" Style="{StaticResource menuButtonText}"/>
                        </StackPanel>                        
                    </RadioButton>

                    <RadioButton Style="{StaticResource menuButton}"
                                 Tag="{StaticResource color2}"
                                 Command="{Binding ShowCustomerViewCommand}">
                        <StackPanel Orientation="Horizontal">
                            <fa:IconImage Icon="UserGroup" Style="{StaticResource menuButtonIcon}"/>
                            <TextBlock Text="Customers" Style="{StaticResource menuButtonText}"/>
                        </StackPanel>
                    </RadioButton>

                </StackPanel>

            </Border>
            
            <!--Main Section-->
            <Border CornerRadius="0,10,10,0"
                    Grid.Column="1">

                <Border.Background>
                    <LinearGradientBrush StartPoint="1,1" EndPoint="0,0">
                        <GradientStop Color="{StaticResource primaryBackColor1}" Offset="0"/>
                        <GradientStop Color="{StaticResource primaryBackColor2}" Offset="1"/>
                    </LinearGradientBrush>
                </Border.Background>

                <Grid>

                    <Grid.RowDefinitions>
                        <!--Control bar-->
                        <RowDefinition Height="25"/>
                        <!--Header / Caption-->
                        <RowDefinition Height="35"/>
                        <!--Content section / Child views-->
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>

                    <!--Control bar-->
                    <StackPanel x:Name="pnlControlBar"
                                Grid.Row="0"
                                Orientation="Horizontal"
                                FlowDirection="RightToLeft"
                                Background="Transparent"
                                Margin="0,0,5,0"
                                MouseLeftButtonDown="pnlControlBar_MouseLeftButtonDown"
                                MouseEnter="pnlControlBar_MouseEnter">

Código de la vista principal

using System.Runtime.InteropServices;
using System.Windows.Interop;

namespace WPF_LoginForm.Views
{
    /// <summary>
    /// Interaction logic for MainWindowView.xaml
    /// </summary>
    public partial class MainView : Window
    {
        public MainView()
        {
            InitializeComponent();
           
        }

        [DllImport("user32.dll")]
        public static extern IntPtr SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam);

        private void pnlControlBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            WindowInteropHelper helper = new WindowInteropHelper(this);
            SendMessage(helper.Handle, 161, 2, 0);
        }

        private void pnlControlBar_MouseEnter(object sender, MouseEventArgs e)
        {
            this.MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight;
        }

        private void btnClose_Click(object sender, RoutedEventArgs e)
        {
            Application.Current.Shutdown();
        }

        private void btnMinimize_Click(object sender, RoutedEventArgs e)
        {
            this.WindowState = WindowState.Minimized;
        }

        private void btnMaximize_Click(object sender, RoutedEventArgs e)
        {
            if (this.WindowState == WindowState.Normal)
                this.WindowState = WindowState.Maximized;
            else this.WindowState = WindowState.Normal;
        }
    }