1. Si vous venez d'arriver sur le forum et que vous êtes un peu perdus, cliquez ici !
    Rejeter la notice

Autres [.NET] Design propre pour son launcher en WPF

Discussion dans 'Tutoriels' créé par Hawezo, 6 Mar 2016.

  1. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    546
    Points:
    136
    Sexe:
    Homme
    Salut tout le monde,

    Dans le cadre de mes tutoriels sur la création d'un launcher Minecraft, je vais vous apprendre à créer une interface propre et acceptable pour votre launcher.
    La particularité ici est que je vais travailler en WPF et non en WinForms, qui de toute façon a été abandonné il y a belle lurette.

    Pour information, il est tout à fait aisé de passer de WinForms à WPF, c'est simplement une question d'habitude, et vous trouverez ça génial (c'est un peu comme passer d'un texture pack *16 à un *64 avec shaders).

    Je vous invite donc à créer un nouveau projet WPF, si vous n'en avez pas déjà un.
    Je détaillerai au possible les étapes.


    [​IMG]

    I. Conseils avant de commencer

    Avant de commencer quoi que ce soit, je vais vous donner quelques exemples en image de ce qu'il ne faut pas faire.


    1. Évitez le trop-plein de couleurs

    Les couleurs, c'est quelque chose de très important, que ce soit dans la création d'un logiciel ou d'une image.
    S'il y a quelque chose que tout le monde aime, même sans s'en rendre compte, c'est l'uniformité des couleurs.

    Si votre lanceur contient des couleurs trop flashy, ce sera désagréable de le regarder ; hors, ce n'est pas le but.
    Pour cela, optez pour une combinaison de couleurs ayant du sens et se mariant bien.

    [​IMG]
    Figure 1 - Exemple de couleurs mal gérées

    Si j'avais un conseil à vous donner, ce serait d'adopter le style Material UI de Google.
    En effet, les couleurs conseillées dans la documentation de cette charte graphique sont étudiées pour correspondre entre elles, et sont par ce fait très agréable à l’œil.

    Pour ceux qui lisent l'anglais et sont intéressés par le Material Design, je vous invite à lire cette page.
    Les autres, je vous invite à mettre cette page en favoris.


    2. Les autres détails
    • Les textes en gras
      Quelque chose d’extrêmement désagréable à voir sur un formulaire quelconque, que ce soit un lanceur Minecraft ou autre, est un texte en gras mal géré. Si vous comptez mettre quelque chose en évidence, utilisez des polices comme Roboto Medium, mais ne mettez pas du gras, car les polices rendent souvent très mal sur un formulaire.
    • Les fautes d’orthographe
      Une faute de frappe c’est vite arrivé, mais si vous n’êtes pas capables d’aligner 10 mots sans faire une faute d’orthographe, utilisez un p*tain de correcteur orthographique. Rien de plus désagréable que de lire un texte rempli de fautes, et je ne suis pas le seul de cet avis. De plus, un rendu sans faute rendra votre lanceur plus professionnel.
    • Les mauvais alignements
      Quand vous alignez des contrôles (que nous verrons plus tard) tels que des étiquettes (labels), boutons, ou autres éléments graphiques, veillez à ce qu’ils soient alignés (vous pouvez vous aider des valeurs numériques des propriétés Size et Location, de la propriété Dock, et de la barre d'outils Disposition)
    • Évitez les ombres et le biseautage
      Hormis sur les cadres (panels), les ombres sont à proscrire. De même, le biseautage dans un nom de serveur écrit à la va-vite sur une version tout à fait légale de Photoshop.
      Ce sont notamment des points clés de la charte graphique Material UI de Google.

    II. L'apparence principale

    1. L'image de fond

    Le fond est quelque chose d'assez important dans une fenêtre, puisque c'est la chose que l'on remarque en premier, du moins la plupart du temps, lorsqu'aucun autre élément n'est tape-à-l’œil.

    J'ai personnellement choisi une image peu originale, mais ayant l'avantage d'être à la fois jolie et polyvalente.

    [​IMG]
    Figure 2 - L'image de fond que je vais utiliser
    Vous pouvez faire Clic droit › Afficher › Enregistrer l'image sous... pour la télécharger


    Le WPF ayant ses avantages, voici le code XAML actuel (rien de bien folichon pour le moment) :
    Code (xml):

    <Window x:Name="Lanceur" x:Class="Graphical_Launcher.MainWindow"
     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:Graphical_Launcher"
     mc:Ignorable="d"
     Title="Lanceur" Height="600" Width="1000" WindowStyle="None" ResizeMode="NoResize">
      <Window.Background>
      <ImageBrush ImageSource="/Graphical Launcher;component/Resources/background.png" Stretch="UniformToFill"/>
      </Window.Background>
      <Grid>
      </Grid>
    </Window>
     
    Vous aurez remarqué le passage de la propriété WindowStyle à None pour enlever les contours, ainsi que la modification du titre, de la largeur et de la hauteur.



    [​IMG]
    Figure 3 - Propriétés de l'image de fond


    2. Les bordures

    Nous allons maintenant placer des bordures, afin de rendre le tout plus esthétique.
    Créez un contrôle Border à l'intérieur du Grid, avec les propriétés BorderBrush à #99000000 et BorderThickness à 2.

    Pour ceux ayant travaillé en WinForms, vous noterez la simplicité acquise avec WPF pour créer des bordures. :)

    Code (xml):

    <Border x:Name="WindowBorders" BorderBrush="#99000000" BorderThickness="2" />
     

    3. La boîte de contrôle personnalisée

    Nous avons enlevé les contours, et maintenant le seul moyen de fermer la fenêtre est un bon vieux Alt + F4, ou un stop violent à partir de Visual Studio.
    Nous allons donc créer notre boîte de contrôle.

    a. Un rectangle pour le fond

    Créez un rectangle de hauteur 38 pixels et de transparence 60%. Il sera utilisé pour le fond de la boîte de contrôle.

    Voici son code XAML :
    Code (xml):

    <Rectangle x:Name="ControlBox" Fill="#99000000" Height="38" Margin="2,2,2,0" VerticalAlignment="Top"/>
     
    b. Une étiquette pour les boutons

    Nous allons commencer par créer un style, puisqu'il est inutile de réécrire le même code pour deux boutons.
    Ce style devra comporter les propriétés communes aux deux boutons : Background et BorderBrush à Transparent, FontFamily à /Graphical Launcher;component/Resources/#Material Icons, HorizontalAlignment et VerticalAlignment à Right et Top, HorizontalContentAlignment et VerticalContentAlignment à Center, Height et Width à 40, TextHintingMode à Animated, FontSize à 22.5, Cursor à Hand, et Foreground à #FFBDBDBD (le blanc pur, c'est trop clair).
    Ce style devra être entre les balises <Windows.Resources>, devra cibler les Labels et porter un nom explicitant son but.

    Voici le code XAML :
    Code (xml):

    <Style x:Key="ControlBoxLabel" TargetType="Label">
      <Setter Property="Background" Value="Transparent"/>
      <Setter Property="BorderBrush" Value="Transparent"/>
      <Setter Property="FontFamily" Value="/Graphical Launcher;component/Resources/#Material Icons"/>
      <Setter Property="HorizontalAlignment" Value="Right"/>
      <Setter Property="VerticalAlignment" Value="Top"/>
      <Setter Property="HorizontalContentAlignment" Value="Center"/>
      <Setter Property="VerticalContentAlignment" Value="Center"/>
      <Setter Property="Height" Value="38"/>
      <Setter Property="Width" Value="38"/>
      <Setter Property="TextOptions.TextHintingMode" Value="Animated"/>
      <Setter Property="FontSize" Value="22.667"/>
      <Setter Property="Foreground" Value="#FFBDBDBD"/>
      <Setter Property="Cursor" Value="Hand"/>
    </Style>
     
    Vous pouvez maintenant créez vos deux étiquettes, avec comme nom LBL_CLOSE et LBL_REDUCE, et les propriétés Content respectivement à &xe5cd;, et &#xe5cf;, ainsi que la propriété Style à {StaticResource ControlBoxLabel}ControlBoxLabel est le nom de votre style.
    Il faut aussi déplacer l'étiquette de réduction de 40 pixels à gauche, sa propriété Margin doit donc être mise à "0,0,40,0".
    Nous avons nos deux boutons de fermeture et réduction ; il reste maintenant à régler l'erreur que vous devez avoir à cause de la police d'écriture.

    c. Police d'écriture personnalisée

    Afin de rendre les étiquettes jolies, je vous invite à utiliser la police d'écriture Material Icons, celle que nous avons mis en lien dans le style, sans l'avoir importée.
    Téléchargez-la et importez-la dans votre projet ; et mettez-y les même propriétés que pour background.png, sinon votre application va planter au démarrage.
    J'en profite pour vous faire télécharger la police Roboto, que nous allons utiliser aussi.


    [​IMG]
    Figure 4 - Téléchargement de la police Roboto

    d. L'icône et le titre

    Il vous faut maintenant choisir une icône. À ce point, vous avez deux options :

    1. Vous avez déjà une d'icône
    Vous pouvez le convertir si ce n’est déjà fait sur le site ConvertIco.


    2. Vous n'avez pas d'icône
    Pour ma part, j’ai pris un logo sur IconFinder, que j’ai converti en icône sur ConvertIco, et j’ai ajouté des marges au fichier original sur Paint .NET. J’suis quelqu'un de polyvalent, moi.

    [​IMG]
    Figure 5 - Le logo que j'ai choisi pour mon lanceur

    Après avoir choisi votre icône, il vous reste à créer un contrôle Image avec les propriétés HorizontalAlignment à Left, VerticalAlignment à Top, et de taille 40 pixels.
    La propriété Source doit être le chemin vers le logo préalablement placé dans vos ressources, soit quelque chose comme /Graphical Launcher;component/Resources/logo.png.

    Voici le code XAML :
    Code (xml):

    <Image x:Name="IMG_LOGO" HorizontalAlignment="Left" Height="40" VerticalAlignment="Top" Width="40" Source="/Graphical Launcher;component/Resources/logo_margin.png" Stretch="Fill" />
     
    Enfin, pour le titre, vous devrez importer la police Roboto Thin, Regular et Medium dans vos ressources, et créer une nouvelle étiquette avec les propriétés suivantes : Font Family à #Roboto Medium, Content à Lanceur Minecraft (ou ce que vous voulez, mais évitez le franglais du genre "Launcher by Albertodu84" ou la version du genre "Modpackcraft v02", qui ne font pas du tout professionnels), HorizontalAlignment à Left, VerticalAlignment à Top, VerticalContentAlignment à Center, Height à 40, TextHintingMode à Animated, FontSize à 18.5, et MaxWidth à 800.

    Voici le code XAML :
    Code (xml):

    <Label x:Name="LBL_NAME" FontFamily="/Graphical Launcher;component/Resources/#Roboto Medium" Content="Lanceur Minecraft" HorizontalAlignment="Left" VerticalAlignment="Top" VerticalContentAlignment="Center" Height="40" Foreground="White" TextOptions.TextHintingMode="Animated" FontSize="18.667" Background="{x:Null}" Margin="40,0,0,0" MaxWidth="800" />
     
    Votre XAML devrait, pour le moment, ressembler à ça :
    Code (xml):

    <Window x:Name="Lanceur" x:Class="Graphical_Launcher.MainWindow"
     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:Graphical_Launcher"
     mc:Ignorable="d"
     Title="Lanceur" Height="600" Width="1000" WindowStyle="None" ResizeMode="NoResize">
     
      <!-- Background -->
      <Window.Background>
      <ImageBrush ImageSource="/Graphical Launcher;component/Resources/background.png" Stretch="UniformToFill"/>
      </Window.Background>

      <!-- Resources -->
      <Window.Resources>

      <!-- ControlBox Label -->
      <Style x:Key="ControlBoxLabel" TargetType="Label">
      <Setter Property="Background" Value="Transparent"/>
      <Setter Property="BorderBrush" Value="Transparent"/>
      <Setter Property="FontFamily" Value="/Graphical Launcher;component/Resources/#Material Icons"/>
      <Setter Property="HorizontalAlignment" Value="Right"/>
      <Setter Property="VerticalAlignment" Value="Top"/>
      <Setter Property="HorizontalContentAlignment" Value="Center"/>
      <Setter Property="VerticalContentAlignment" Value="Center"/>
      <Setter Property="Height" Value="40"/>
      <Setter Property="Width" Value="40"/>
      <Setter Property="TextOptions.TextHintingMode" Value="Animated"/>
      <Setter Property="FontSize" Value="22.667"/>
      <Setter Property="Foreground" Value="#FFBDBDBD"/>
      <Setter Property="Cursor" Value="Hand"/>
      </Style>

      </Window.Resources>

      <!-- Content -->
      <Grid>
      <Rectangle x:Name="ControlBox" Fill="#99000000" Height="40" Margin="0" VerticalAlignment="Top"/>
      <Label x:Name="LBL_CLOSE" Style="{StaticResource ControlBoxLabel}" Content="&#xe5cd;" MouseLeftButtonUp="LBL_CLOSE_MouseLeftButtonUp" />
      <Label x:Name="LBL_REDUCE" Style="{StaticResource ControlBoxLabel}" Content="&#xe5cf;" Margin="0,0,40,0" MouseLeftButtonUp="LBL_REDUCE_MouseLeftButtonUp" />
      <Image x:Name="IMG_LOGO" HorizontalAlignment="Left" Height="40" VerticalAlignment="Top" Width="40" Source="/Graphical Launcher;component/Resources/logo_margin.png" Stretch="Fill" />
      <Label x:Name="LBL_NAME" FontFamily="/Graphical Launcher;component/Resources/#Roboto Medium" Content="Lanceur Minecraft" HorizontalAlignment="Left" VerticalAlignment="Top" VerticalContentAlignment="Center" Height="40" Foreground="White" TextOptions.TextHintingMode="Animated" FontSize="18.667" Background="{x:Null}" Margin="40,0,0,0" MaxWidth="800" />
      </Grid>
    </Window>

     
    3. Les animations

    Ceci étant fait, nous allons animer nos boutons de réduction et de fermeture, pour un meilleur rendu.
    Cette partie devient relativement intéressante, puisque nous allons voir l'héritance des styles en WPF.

    Je vous invite à éditer votre style ControlBoxLabel et d'y ajouter le code suivant :
    Code (xml):

    <Style.Triggers>
      <Trigger Property="IsMouseOver" Value="True">

      <!-- On MouseOver -->
      <Trigger.EnterActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Background).(SolidColorBrush.Color)"
     From="#00000000" To="#3F000000" Duration="0:0:0.250" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.EnterActions>

      <!-- On MouseLeave -->
      <Trigger.ExitActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Background).(SolidColorBrush.Color)"
     From="#3F000000" To="#00000000" Duration="0:0:0.250" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.ExitActions>
      </Trigger>
      </Style.Triggers>
    </Style>
     
    Ce code permet, au déclenchement de l'évènement IsMouseOver (ligne 2) de lancer une animation en fonction de la valeur de la propriété IsMouseOver (booléenne), d'une durée de 250 millisecondes.
    Quand vous passerez votre souris sur l'étiquette, l'animation (ColorAnimation) à la ligne 8 (EnterAction) se déclenchera, et fera passer l'opacité du fond de votre label à 25%, et l'inverse lorsque vous quitterez l'étiquette (ligne 15).

    Vous pouvez lancer et voir le résultat.

    Je vais aller plus loin en modifiant séparemment la couleur du texte des étiquettes ; soit en rouge pour la fermeture et en bleu pour la réduction.
    Je vous invite à choisir les couleurs qui vous intéresse sur la page des couleurs Material de Google.
    Pour moi ce sera le code 300 rouge (#e57373) pour la fermeture et le code 300 bleu (#4FC3F7) pour la réduction.

    Une fois vos couleurs choisies, créez un nouvel évènement ControlBoxCloseLabel avec la propriété BasedOn à {StaticResource ControlBoxLabel} (principe d'héritance) et avec deux animations jouant sur la propriété Label.Foreground qui ira vers votre couleur, et qui sera d'une durée de 500 millisecondes.

    Voici le code XAML :
    Code (xml):

    <!-- Close button -->
      <Style x:Key="ControlBoxCloseLabel" TargetType="Label" BasedOn="{StaticResource ControlBoxLabel}">
      <Style.Triggers>
      <Trigger Property="IsMouseOver" Value="True">

      <!-- On MouseOver -->
      <Trigger.EnterActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Foreground).(SolidColorBrush.Color)"
     From="#FFBDBDBD" To="#ffe57373" Duration="0:0:0.500" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.EnterActions>

      <!-- On MouseLeave -->
      <Trigger.ExitActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Foreground).(SolidColorBrush.Color)"
     From="#ffe57373" To="#FFBDBDBD" Duration="0:0:0.500" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.ExitActions>
      </Trigger>
      </Style.Triggers>
    </Style>
     

    Vous pouvez maintenant faire pareil pour le bouton de réduction en changeant les couleurs et le nom.
    En voici le code XAML :
    Code (cpp):

    <!-- Close button -->
      <Style x:Key="ControlBoxReduceLabel" TargetType="Label" BasedOn="{StaticResource ControlBoxLabel}">
      <Style.Triggers>
      <Trigger Property="IsMouseOver" Value="True">

      <!-- On MouseOver -->
      <Trigger.EnterActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Foreground).(SolidColorBrush.Color)"
      From="#FFBDBDBD" To="#ff4FC3F7" Duration="0:0:0.500" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.EnterActions>

      <!-- On MouseLeave -->
      <Trigger.ExitActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Foreground).(SolidColorBrush.Color)"
      From="#ff4FC3F7" To="#FFBDBDBD" Duration="0:0:0.500" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.ExitActions>
      </Trigger>
      </Style.Triggers>
    </Style>
     
    Vous n'avez plus qu'à changer la propriété Style de vos étiquette en ControlBoxReduceLabel et ControlBoxCloseLabel, et tester !

    [​IMG]
    Figure 6 - État actuel de mon lanceur

    Pour résumer, voici le code complet.
    Code (xml):

    <Window x:Name="Lanceur" x:Class="Graphical_Launcher.MainWindow"
     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:Graphical_Launcher"
     mc:Ignorable="d"
     Title="Lanceur" Height="600" Width="1000" WindowStyle="None" ResizeMode="NoResize">
     
      <!-- Background -->
      <Window.Background>
      <ImageBrush ImageSource="/Graphical Launcher;component/Resources/background.png" Stretch="UniformToFill"/>
      </Window.Background>

      <!-- Resources -->
      <Window.Resources>

      <!-- ControlBox Label -->
      <Style x:Key="ControlBoxLabel" TargetType="Label">
      <Setter Property="Background" Value="Transparent"/>
      <Setter Property="BorderBrush" Value="Transparent"/>
      <Setter Property="FontFamily" Value="/Graphical Launcher;component/Resources/#Material Icons"/>
      <Setter Property="HorizontalAlignment" Value="Right"/>
      <Setter Property="VerticalAlignment" Value="Top"/>
      <Setter Property="HorizontalContentAlignment" Value="Center"/>
      <Setter Property="VerticalContentAlignment" Value="Center"/>
      <Setter Property="Height" Value="40"/>
      <Setter Property="Width" Value="40"/>
      <Setter Property="TextOptions.TextHintingMode" Value="Animated"/>
      <Setter Property="FontSize" Value="22.667"/>
      <Setter Property="Foreground" Value="#FFBDBDBD"/>
      <Setter Property="Cursor" Value="Hand"/>

      <Style.Triggers>
      <Trigger Property="IsMouseOver" Value="True">

      <!-- On MouseOver -->
      <Trigger.EnterActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Background).(SolidColorBrush.Color)"
     From="#00000000" To="#3F000000" Duration="0:0:0.250" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.EnterActions>

      <!-- On MouseLeave -->
      <Trigger.ExitActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Background).(SolidColorBrush.Color)"
     From="#3F000000" To="#00000000" Duration="0:0:0.250" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.ExitActions>
      </Trigger>
      </Style.Triggers>
      </Style>
     
      <!-- Close button -->
      <Style x:Key="ControlBoxCloseLabel" TargetType="Label" BasedOn="{StaticResource ControlBoxLabel}">
      <Style.Triggers>
      <Trigger Property="IsMouseOver" Value="True">

      <!-- On MouseOver -->
      <Trigger.EnterActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Foreground).(SolidColorBrush.Color)"
     From="#FFBDBDBD" To="#ffe57373" Duration="0:0:0.500" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.EnterActions>

      <!-- On MouseLeave -->
      <Trigger.ExitActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Foreground).(SolidColorBrush.Color)"
     From="#ffe57373" To="#FFBDBDBD" Duration="0:0:0.500" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.ExitActions>
      </Trigger>
      </Style.Triggers>
      </Style>

      <!-- Close button -->
      <Style x:Key="ControlBoxReduceLabel" TargetType="Label" BasedOn="{StaticResource ControlBoxLabel}">
      <Style.Triggers>
      <Trigger Property="IsMouseOver" Value="True">

      <!-- On MouseOver -->
      <Trigger.EnterActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Foreground).(SolidColorBrush.Color)"
     From="#FFBDBDBD" To="#ff4FC3F7" Duration="0:0:0.500" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.EnterActions>

      <!-- On MouseLeave -->
      <Trigger.ExitActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Foreground).(SolidColorBrush.Color)"
     From="#ff4FC3F7" To="#FFBDBDBD" Duration="0:0:0.500" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.ExitActions>
      </Trigger>
      </Style.Triggers>
      </Style>

      </Window.Resources>

      <!-- Content -->
      <Grid>
      <Border x:Name="WindowBorders" BorderBrush="#99000000" BorderThickness="2" />
     
      <!-- Control Box -->
      <Rectangle x:Name="ControlBox" Fill="#99000000" Height="38" Margin="2,2,2,0" VerticalAlignment="Top"/>
      <Label x:Name="LBL_CLOSE" Style="{StaticResource ControlBoxCloseLabel}" Content="&#xe5cd;"  />
      <Label x:Name="LBL_REDUCE" Style="{StaticResource ControlBoxReduceLabel}" Content="&#xe5cf;" Margin="0,0,40,0" />
      <Image x:Name="IMG_LOGO" HorizontalAlignment="Left" Height="40" VerticalAlignment="Top" Width="40" Source="/Graphical Launcher;component/Resources/logo_margin.png" Stretch="Fill" />
      <Label x:Name="LBL_NAME" FontFamily="/Graphical Launcher;component/Resources/#Roboto Medium" Content="Lanceur Minecraft" HorizontalAlignment="Left" VerticalAlignment="Top" VerticalContentAlignment="Center" Height="40" Foreground="White" TextOptions.TextHintingMode="Animated" FontSize="18.667" Background="{x:Null}" Margin="40,0,0,0" MaxWidth="800" />
      </Grid>
    </Window>
     

    III. Le code de fermeture et réduction

    Nous en somme à la partie la plus simple, soit le code de fermeture et de réduction.
    Commencez par mettre la propriété AllowTransparency de notre Window à True.
    Ajoutez ensuite ce code dans vos resources :
    Code (xml):

    <!-- Window Close Fade -->
      <Storyboard x:Key="WindowClose" Completed="closeStoryBoard_Completed">
      <DoubleAnimation Storyboard.TargetProperty="Opacity" To="0" From="1" Duration="0:0:0.250" Storyboard.TargetName="Lanceur" />
      </Storyboard>
     
    En remplaçant bien entendu Lanceur par le nom de votre fenêtre. Vous pouvez également changer le temps.
    Il permettra, lors de son appel, de faire fondre la fenêtre.

    Ouvrez maintenant l'évènement MouseLeftButtonUp de votre LBL_CLOSE.

    [​IMG]
    Figure 7 - Évènement MouseLeftButtonUp

    L'éditeur de code s'affiche et le code XAML s'est modifié pour lier cette nouvelle méthode à l'évènement.
    Écrivez simplement this.Close(); dans cette méthode.

    Créez ensuite une variable globale privée et booléenne nommée closeStoryBoardCompleted.
    Ouvrez l'évènement Closing de votre Window.
    Insérez-y le code suivant :
    Code (csharp):

    if (!closeStoryBoardCompleted)
      {
      Storyboard WindowClose = this.FindResource("WindowClose") as Storyboard;
      WindowClose.Begin();
      e.Cancel = true;
      }
     
    Remplacez bien entendu WindowClose par le nom de votre Storyboard, et n'oubliez pas d'importer Windows.Media.Animation et ComponentModel.
    Ce code permet de lancer l'animation en d'empêcher la fermeture (en attendant que l'animation se termine), si et seulement si la variable closeStoryBoardCompleted est à False.

    Maintenant, vous pouvez ajouter la méthode appelée à la fin de l'animation, soit :
    Code (csharp):

    private void closeStoryBoard_Completed(object sender, EventArgs e)
      {
      closeStoryBoardCompleted = true;
      this.Close();
      }
     
    Ici, rien de particulier à comprendre, si ce n'est qu'on passe la variable closeStoryBoardCompleted à True afin de ne pas gêner l'évènement de fermeture.

    Vous pouvez essayer de cliquer sur le bouton de fermeture, et votre fenêtre se fermera en fondu !

    Pour la réduction, c'est aussi simple que d'écrire this.WindowState = WindowState.Minimized; dans la méthode de l'évènement MouseLeftButtonUp du LBL_REDUCE.
    Bien que ce soit possible, j'ai décidé de ne pas mettre d'animation à la réduction pour le moment.


    IV. Pour résumer

    Voici le code XAML complet :
    Code (xml):

    <Window x:Name="Lanceur" x:Class="Graphical_Launcher.MainWindow"
     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:Graphical_Launcher"
     mc:Ignorable="d"
     Title="Lanceur" Height="600" Width="1000" WindowStyle="None" ResizeMode="NoResize" Closing="Lanceur_Closing" AllowsTransparency="True">

      <!-- Background -->
      <Window.Background>
      <ImageBrush ImageSource="/Graphical Launcher;component/Resources/background.png" Stretch="UniformToFill"/>
      </Window.Background>

      <!-- Resources -->
      <Window.Resources>

      <!-- Window Close Fade -->
      <Storyboard x:Key="WindowClose" Completed="closeStoryBoard_Completed">
      <DoubleAnimation Storyboard.TargetProperty="Opacity" To="0"  Duration="0:0:0.250" Storyboard.TargetName="Lanceur" />
      </Storyboard>

      <!-- ControlBox Label -->
      <Style x:Key="ControlBoxLabel" TargetType="Label">
      <Setter Property="Background" Value="Transparent"/>
      <Setter Property="BorderBrush" Value="Transparent"/>
      <Setter Property="FontFamily" Value="/Graphical Launcher;component/Resources/#Material Icons"/>
      <Setter Property="HorizontalAlignment" Value="Right"/>
      <Setter Property="VerticalAlignment" Value="Top"/>
      <Setter Property="HorizontalContentAlignment" Value="Center"/>
      <Setter Property="VerticalContentAlignment" Value="Center"/>
      <Setter Property="Height" Value="40"/>
      <Setter Property="Width" Value="40"/>
      <Setter Property="TextOptions.TextHintingMode" Value="Animated"/>
      <Setter Property="FontSize" Value="22.667"/>
      <Setter Property="Foreground" Value="#FFBDBDBD"/>
      <Setter Property="Cursor" Value="Hand"/>

      <Style.Triggers>
      <Trigger Property="IsMouseOver" Value="True">

      <!-- On MouseOver -->
      <Trigger.EnterActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Background).(SolidColorBrush.Color)"
     From="#00000000" To="#3F000000" Duration="0:0:0.250" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.EnterActions>

      <!-- On MouseLeave -->
      <Trigger.ExitActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Background).(SolidColorBrush.Color)"
     From="#3F000000" To="#00000000" Duration="0:0:0.250" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.ExitActions>
      </Trigger>
      </Style.Triggers>
      </Style>

      <!-- Close button -->
      <Style x:Key="ControlBoxCloseLabel" TargetType="Label" BasedOn="{StaticResource ControlBoxLabel}">
      <Style.Triggers>
      <Trigger Property="IsMouseOver" Value="True">

      <!-- On MouseOver -->
      <Trigger.EnterActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Foreground).(SolidColorBrush.Color)"
     From="#FFBDBDBD" To="#ffe57373" Duration="0:0:0.500" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.EnterActions>

      <!-- On MouseLeave -->
      <Trigger.ExitActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Foreground).(SolidColorBrush.Color)"
     From="#ffe57373" To="#FFBDBDBD" Duration="0:0:0.500" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.ExitActions>
      </Trigger>
      </Style.Triggers>
      </Style>

      <!-- Close button -->
      <Style x:Key="ControlBoxReduceLabel" TargetType="Label" BasedOn="{StaticResource ControlBoxLabel}">
      <Style.Triggers>
      <Trigger Property="IsMouseOver" Value="True">

      <!-- On MouseOver -->
      <Trigger.EnterActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Foreground).(SolidColorBrush.Color)"
     From="#FFBDBDBD" To="#ff4FC3F7" Duration="0:0:0.500" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.EnterActions>

      <!-- On MouseLeave -->
      <Trigger.ExitActions>
      <BeginStoryboard>
      <Storyboard>
      <ColorAnimation Storyboard.TargetProperty="(Label.Foreground).(SolidColorBrush.Color)"
     From="#ff4FC3F7" To="#FFBDBDBD" Duration="0:0:0.500" />
      </Storyboard>
      </BeginStoryboard>
      </Trigger.ExitActions>
      </Trigger>
      </Style.Triggers>
      </Style>

      </Window.Resources>

      <!-- Content -->
      <Grid>
      <Border x:Name="WindowBorders" BorderBrush="#99000000" BorderThickness="2" />

      <!-- Control Box -->
      <Rectangle x:Name="ControlBox" Fill="#99000000" Height="38" Margin="2,2,2,0" VerticalAlignment="Top"/>
      <Label x:Name="LBL_CLOSE" Style="{StaticResource ControlBoxCloseLabel}" Content="&#xe5cd;" MouseLeftButtonUp="LBL_CLOSE_MouseLeftButtonUp"  />
      <Label x:Name="LBL_REDUCE" Style="{StaticResource ControlBoxReduceLabel}" Content="&#xe5cf;" Margin="0,0,40,0" MouseLeftButtonUp="LBL_REDUCE_MouseLeftButtonUp" />
      <Image x:Name="IMG_LOGO" HorizontalAlignment="Left" Height="40" VerticalAlignment="Top" Width="40" Source="/Graphical Launcher;component/Resources/logo_margin.png" Stretch="Fill" />
      <Label x:Name="LBL_NAME" FontFamily="/Graphical Launcher;component/Resources/#Roboto Medium" Content="Lanceur Minecraft" HorizontalAlignment="Left" VerticalAlignment="Top" VerticalContentAlignment="Center" Height="40" Foreground="White" TextOptions.TextHintingMode="Animated" FontSize="18.667" Background="{x:Null}" Margin="40,0,0,0" MaxWidth="800" />
      </Grid>
    </Window>
     
    Ainsi que le code-behind complet (il est très mal organisé, mais ce n'était pas le but de ce tutoriel) :
    Code (csharp):

    using System;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media.Animation;

    namespace Graphical_Launcher
    {
      /// <summary>
      /// Logique d'interaction pour MainWindow.xaml
      /// </summary>
      public partial class MainWindow : Window
      {
      // Variables
      private bool closeStoryBoardCompleted = false;

      // Constructor
      public MainWindow()
      {
      InitializeComponent();
      }

      // Storyboard's end event
      private void closeStoryBoard_Completed(object sender, EventArgs e)
      {
      closeStoryBoardCompleted = true;
      this.Close();
      }

      // Form closing event
      private void Lanceur_Closing(object sender, CancelEventArgs e)
      {
      if (!closeStoryBoardCompleted)
      {
      Storyboard WindowClose = this.FindResource("WindowClose") as Storyboard;
      WindowClose.Begin();
      e.Cancel = true;
      }
      }

      // Button close event
      private void LBL_CLOSE_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
      {
      this.Close();
      }

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

    [​IMG]


    Vous savez maintenant créer un design largement potable en WPF, et avez quelques conseils pour la création d'un design original.
    Vous n'avez plus d'excuses, vous pouvez créer un joli lanceur ! :)

    Si j'ai oublié quelque chose, ou que vous avez besoin de détails, n'hésitez pas à commenter.
     
    • J'aime J'aime x 2
    • J'approuve J'approuve x 1
    • Utile Utile x 1
  2. Pikachu

    Pikachu Mineur

    Inscrit:
    26 Avr 2014
    Messages:
    393
    Points:
    89
    Sexe:
    Homme
    Sooooooooooooooooooooooooooooooooooooooooooooooooooooooooo maaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaany teeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeexts.

    C'est bien fait, c'est cool. :3
     
    • J'aime J'aime x 1
    • Sympa Sympa x 1
    #2 Pikachu, 6 Mar 2016
    Dernière édition: 6 Mar 2016
  3. Polymeth

    Polymeth Mineur de Diamants

    Inscrit:
    16 Août 2014
    Messages:
    2 135
    Points:
    150
    Sexe:
    Homme
    Bon, je vais essayer ça, vu que je n'ai jamais tenté le WPF, et que ça à l'air franchement cool.
     
    • J'aime J'aime x 1
    • J'approuve J'approuve x 1
  4. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    546
    Points:
    136
    Sexe:
    Homme
    Cool. Tu pourra en profiter pour me dire si j'ai fais des oublis ou si j'ai mal expliqué quelque chose ?
    Bonne chance (et je t'invite à poster un screen de ton résultat final o/)
     
    • J'approuve J'approuve x 2
  5. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    546
    Points:
    136
    Sexe:
    Homme
    @Polymeth j'passais par là, et j'ai relu le commentaire, tu as fais quelque chose du coup ?
     
    • Informatif Informatif x 1
  6. Polymeth

    Polymeth Mineur de Diamants

    Inscrit:
    16 Août 2014
    Messages:
    2 135
    Points:
    150
    Sexe:
    Homme
    Je vais justement le faire, là. :)
     
    • Informatif Informatif x 2
  7. Sylfaen

    Sylfaen Mineur de Redstone

    Inscrit:
    18 Avr 2016
    Messages:
    1 171
    Points:
    123
    Sexe:
    Homme
    @Hawezo Une question qui va peut-être te paraitre "conne", mais est-ce possible d'intégrer du HTML/CSS/JS pour le design du launcher ? Ne m'en veut pas si je dis n'importe quoi :'(
     
    • J'aime J'aime x 1
    • J'approuve J'approuve x 1
  8. Polymeth

    Polymeth Mineur de Diamants

    Inscrit:
    16 Août 2014
    Messages:
    2 135
    Points:
    150
    Sexe:
    Homme
    En intégrant une page web dans le logiciel, oui. Mais c'est pas super super.
     
    • Informatif Informatif x 1
  9. Sylfaen

    Sylfaen Mineur de Redstone

    Inscrit:
    18 Avr 2016
    Messages:
    1 171
    Points:
    123
    Sexe:
    Homme
    Donc le design doit obligatoirement être réalisé en .net/wpf ? Flûte!
     
    • J'approuve J'approuve x 3
  10. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    546
    Points:
    136
    Sexe:
    Homme
    @Sylfaen Non, ce n'est pas possible, et intégrer une page web n'est absolument pas viable (ça va ralentir genre beaucoup beaucoup, et les évènements vont être horribles à gérer).
    Pour un développeur web, ta question est normale, ne t'en fais pas ^^

    ÉDIT › Et on peut effectivement développer une application .NET à l'aide de Javascript, mais je n'en sais pas plus à ce sujet.
     
    • J'approuve J'approuve x 2
    #10 Hawezo, 23 Avr 2016
    Dernière édition: 31 Jan 2020
  11. Sylfaen

    Sylfaen Mineur de Redstone

    Inscrit:
    18 Avr 2016
    Messages:
    1 171
    Points:
    123
    Sexe:
    Homme
    Dommage, on pourrait faire des choses plus facilement... Oui javascript je le savais pour le .net!
     
    • Informatif Informatif x 1
  12. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    546
    Points:
    136
    Sexe:
    Homme
    @Sylfaen "Plus facilement", tout est relatif. Mais c'est vrai que pour certaines choses, ce serait un vrai plus. Par contre, je t'assure que le WPF offre d'excellentes possibilités au niveau graphismes !
     
    • J'approuve J'approuve x 2
    #12 Hawezo, 29 Avr 2016
    Dernière édition: 31 Jan 2020

Partager cette page