Saltar al contenido

WPF & MVVM – Diseño de IU Principal Moderno – Parte 2 (Final)

Muy bien, continuemos con el tutorial, ahora agregaremos los botones para cerrar, maximizar y minimizar la ventana, diseñar el encabezado de la sección y abrir las vistas secundarias en el contenido de la sección.

Tutorial

Código

Estilos de botón

    <!--Control bar button-->
    <Style x:Key="controlButton" TargetType="Button">
        <!--Normal button style-->
        <Setter Property="Width" Value="35"/>       
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="Foreground" Value="{StaticResource plainTextColor3}"/>      
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border Background="{TemplateBinding Background}"
                            CornerRadius="4">
                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>

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

    <!--Menu button icon-->
    <Style x:Key="controlButtonIcon" TargetType="fa:IconImage">
        <Setter Property="Foreground" Value="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}"/>
        <Setter Property="Width" Value="9"/>
        <Setter Property="Height" Value="9"/>
    </Style>


    <!--Icon button-->
    <Style x:Key="iconButton" TargetType="Button">
        <!--Normal button style-->
        <Setter Property="Cursor" Value="Hand"/>
        <Setter Property="Width" Value="25"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="Foreground" Value="{StaticResource plainTextColor1}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border Background="{TemplateBinding Background}">
                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>

        <Style.Triggers>
            <!--Button Style on hover-->
            <Trigger Property="IsMouseOver" Value="True">        
                <Setter Property="Foreground" Value="{Binding Path=Tag, RelativeSource={RelativeSource Self}}"/>
            </Trigger>
        </Style.Triggers>
    </Style>

    <!--Menu button icon-->
    <Style x:Key="iconButtonIcon" TargetType="fa:IconImage">
        <Setter Property="Foreground" Value="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}"/>
        <Setter Property="Width" Value="16"/>
        <Setter Property="Height" Value="16"/>
    </Style>

Modelos de Vista

ViewModelBase

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

ViewModelCommand

public class ViewModelCommand : ICommand
{
    //Fields
    private readonly Action<object> _executeAction;
    private readonly Predicate<object> _canExecuteAction;

    //Constructors
    public ViewModelCommand(Action<object> executeAction)
    {
        _executeAction = executeAction;
        _canExecuteAction = null;
    }

    public ViewModelCommand(Action<object> executeAction, Predicate<object> canExecuteAction)
    {
        _executeAction = executeAction;
        _canExecuteAction = canExecuteAction;
    }

    //Events
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    //Methods
    public bool CanExecute(object parameter)
    {
        return _canExecuteAction == null ? true : _canExecuteAction(parameter);
    }

    public void Execute(object parameter)
    {
        _executeAction(parameter);
    }
}

HomeViewModel

public class HomeViewModel : ViewModelBase
{

}

CustomerViewModel

public class CustomerViewModel : ViewModelBase
{

}

MainViewModel

public class MainViewModel : ViewModelBase
{
    //Fields
    private UserAccountModel _currentUserAccount;
    private ViewModelBase _currentChildView;
    private string _caption;
    private IconChar _icon;

    private IUserRepository userRepository;

    //Properties
    public UserAccountModel CurrentUserAccount
    {
        get
        {
            return _currentUserAccount;
        }

        set
        {
            _currentUserAccount = value;
            OnPropertyChanged(nameof(CurrentUserAccount));
        }
    }

    public ViewModelBase CurrentChildView
    {
        get
        {
            return _currentChildView;
        }

        set
        {
            _currentChildView = value;
            OnPropertyChanged(nameof(CurrentChildView));
        }
    }

    public string Caption
    {
        get
        {
            return _caption;
        }

        set
        {
            _caption = value;
            OnPropertyChanged(nameof(Caption));
        }
    }

    public IconChar Icon
    {
        get
        {
            return _icon;
        }

        set
        {
            _icon = value;
            OnPropertyChanged(nameof(Icon));
        }
    }

    //--> Commands
    public ICommand ShowHomeViewCommand { get; }
    public ICommand ShowCustomerViewCommand { get; }

    public MainViewModel()
    {
        userRepository = new UserRepository();
        CurrentUserAccount = new UserAccountModel();

        //Initialize commands
        ShowHomeViewCommand = new ViewModelCommand(ExecuteShowHomeViewCommand);
        ShowCustomerViewCommand = new ViewModelCommand(ExecuteShowCustomerViewCommand);

        //Default view
        ExecuteShowHomeViewCommand(null);

        LoadCurrentUserData();
    }

    private void ExecuteShowCustomerViewCommand(object obj)
    {
        CurrentChildView = new CustomerViewModel();
        Caption = "Customers";
        Icon = IconChar.UserGroup;
    }

    private void ExecuteShowHomeViewCommand(object obj)
    {
        CurrentChildView = new HomeViewModel();
        Caption = "Dashboard";
        Icon = IconChar.Home;
    }

Vistas

HomeView

<UserControl x:Class="WPF_LoginForm.Views.HomeView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPF_LoginForm.Views"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Image Source="/Images/dashboard-template.png"/>
    </Grid>
</UserControl>

CustomerView

<UserControl x:Class="WPF_LoginForm.Views.CustomerView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPF_LoginForm.Views" xmlns:fa="http://schemas.awesome.incremented/wpf/xaml/fontawesome.sharp"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="120"/>
            </Grid.ColumnDefinitions>

            <StackPanel Orientation="Horizontal"
                        VerticalAlignment="Top"
                        Grid.Column="0">
                <fa:IconImage Icon="Search" Height="20" Width="20" Foreground="{StaticResource plainTextColor3}"/>

                <TextBox Text="Search..."   
                    FontSize="13"
                         Height="24"
                           Width="300"
                           Background="Transparent"
                             FontWeight="Medium"
                             FontFamily="Montserrat"                            
                             Foreground="{StaticResource plainTextColor3}"
                             CaretBrush="{StaticResource plainTextColor3}"
                             BorderBrush="{StaticResource plainTextColor3}"
                             BorderThickness="0,0,0,1"                             
                             VerticalContentAlignment="Center"
                             Margin="5,5,0,0"></TextBox>

            </StackPanel>

            <Button Grid.Column="1"
                            Command="{Binding LoginCommand}"                            
                            Content="Search"                            
                            FontSize="12"
                            FontFamily="Montserrat"
                            Cursor="Hand"
                            BorderThickness="0"
                            Foreground="White"
                    VerticalAlignment="Top">

                <Button.Style>
                    <Style TargetType="Button">
                        <Setter Property="Background" Value="#773DFF"/>
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="Button">
                                    <Border Height="30"
                                                    CornerRadius="15"
                                                    Background="{TemplateBinding Background}">
                                        <ContentPresenter VerticalAlignment="Center"
                                                                      HorizontalAlignment="Center"/>
                                    </Border>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>

                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Background" Value="#836EFB"/>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Button.Style>
            </Button>
        </Grid>
        <Border Grid.Row="1"
                Background="#200F53"
                CornerRadius="10" 
                Padding="10">

            <DataGrid ColumnWidth="*"
                  Background="#200F53"
                  BorderThickness="0">

                <DataGrid.ColumnHeaderStyle>
                    <Style TargetType="DataGridColumnHeader">
                        <Setter Property="Background" Value="Transparent"/>
                        <Setter Property="Foreground" Value="#BCBEE0"/>
                        <Setter Property="Padding" Value="10,0,0,10"/>
                        <Setter Property="FontFamily" Value="Montserrat"/>
                        <Setter Property="FontSize" Value="15"/>
                    </Style>
                </DataGrid.ColumnHeaderStyle>

                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{x:Null}" ClipboardContentBinding="{x:Null}" Header="ID" HeaderStringFormat=""/>
                    <DataGridTextColumn Binding="{x:Null}" ClipboardContentBinding="{x:Null}" Header="First name"/>
                    <DataGridTextColumn Binding="{x:Null}" ClipboardContentBinding="{x:Null}" Header="Last name"/>
                    <DataGridTextColumn Binding="{x:Null}" ClipboardContentBinding="{x:Null}" Header="Phone"/>
                    <DataGridTextColumn Binding="{x:Null}" ClipboardContentBinding="{x:Null}" Header="Number"/>
                    <DataGridTextColumn Binding="{x:Null}" ClipboardContentBinding="{x:Null}" Header="Address"/>
                </DataGrid.Columns>
            </DataGrid>
        </Border>

    </Grid>
</UserControl>

MainView

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

    <Window.Resources>
        
        <DataTemplate DataType="{x:Type viewModel:HomeViewModel}">
            <local:HomeView/>
        </DataTemplate>

        <DataTemplate DataType="{x:Type viewModel:CustomerViewModel}">
            <local:CustomerView/>
        </DataTemplate>
        
    </Window.Resources>

<!--Here previous code...
get previous code in previous tutorial-->

                    <!--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">

                        <Button x:Name="btnClose"
                                Style="{StaticResource controlButton}"
                                Tag="{StaticResource color4}"
                                Click="btnClose_Click">
                            <fa:IconImage Icon="Xmark" Style="{StaticResource controlButtonIcon}"/>
                        </Button>

                        <Button x:Name="btnMaximize"
                                Style="{StaticResource controlButton}"
                                Tag="{StaticResource color6}"
                                Click="btnMaximize_Click">
                            <fa:IconImage Icon="Square" Style="{StaticResource controlButtonIcon}"/>
                        </Button>

                        <Button x:Name="btnMinimize"
                                Style="{StaticResource controlButton}"
                                Tag="{StaticResource color8}"
                                Click="btnMinimize_Click">
                            <fa:IconImage Icon="WindowMinimize" Width="12" Style="{StaticResource controlButtonIcon}"/>
                        </Button>

                    </StackPanel>

                    <!--Header / Caption-->
                    <Grid Grid.Row="1">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        
                        <!--Caption-->
                        <StackPanel Grid.Column="0"
                                    Orientation="Horizontal"
                                    VerticalAlignment="Center">

                            <fa:IconImage Icon="{Binding Icon}"
                                          Height="20"
                                          Width="20"
                                          Foreground="{StaticResource titleColor2}"
                                          Margin="35,0,10,0"/>
                            
                            <TextBlock Text="{Binding Caption}"
                                       Foreground="{StaticResource titleColor2}"
                                       FontSize="16"
                                       FontFamily="Montserrat"
                                       FontWeight="Medium"
                                       VerticalAlignment="Center"/>
                        </StackPanel>
                        
                        <!--User options-->
                        <StackPanel Grid.Column="1"
                                    Orientation="Horizontal"
                                    FlowDirection="RightToLeft"
                                    VerticalAlignment="Center"
                                    Margin="0,0,10,0">

                            <Button Style="{StaticResource iconButton}"
                                    Tag="{StaticResource color1}">
                                <fa:IconImage Icon="AngleDown"
                                              Height="12" Width="12"
                                              Style="{StaticResource iconButtonIcon}"/>
                            </Button>

                            <TextBlock Text="{Binding CurrentUserAccount.DisplayName}"
                                       Foreground="{StaticResource titleColor3}"
                                       FontFamily="Montserrat"
                                       FontSize="12"
                                       VerticalAlignment="Center"/>

                            <Ellipse Height="35" Width="35"
                                     Stroke="{StaticResource color2}"
                                     StrokeThickness="2"
                                     Margin="10,0,10,0">
                                <Ellipse.Fill>
                                    <ImageBrush ImageSource="/Images/profile-picture.png"/>
                                </Ellipse.Fill>                                
                            </Ellipse>

                            <Button Style="{StaticResource iconButton}"
                                    Tag="{StaticResource color3}">
                                <fa:IconImage Icon="Clock" Style="{StaticResource iconButtonIcon}"/>
                            </Button>

                            <Button Style="{StaticResource iconButton}"
                                    Tag="{StaticResource color4}">
                                <fa:IconImage Icon="Envelope" Style="{StaticResource iconButtonIcon}"/>
                            </Button>

                            <Button Style="{StaticResource iconButton}"
                                    Tag="{StaticResource color5}">
                                <fa:IconImage Icon="Bell" Style="{StaticResource iconButtonIcon}"/>
                            </Button>

                        </StackPanel>
                        
                    </Grid>

                    <!--Content section / Child views-->
                    <ContentControl Content="{Binding CurrentChildView}"
                                    Grid.Row="2"
                                    Margin="25"/>

                </Grid>

            </Border>

        </Grid>

    </Border>

</Window>