Implémentez vos menus Hamburger avec AppShell !

Bonjour à tous!

Dans le cadre du développement d’une application universelle, je voulais une fonctionnalité « bête » mais qui peut vite paraître compliqué si on part from scratch : un menu comme on a sur les applications Microsoft, avec leur fameux hamburgers.

wp_ss_20160615_0002

Exemple sur mon téléphone sous WM10 avec l’application Actualités

Cela peut être assez lourd à mettre en place, surtout si on est amené à faire plusieurs applications (passage par un UserControl ?), et après plusieurs recherches je suis tombé par hasard sur un composant qui fait tout le travail pour nous, magnifique n’est-ce pas?

Aperçu et introduction

Avant de parler plus en détail de ce plugin, voyons le rendu sur un projet UWP avec émulation Windows Mobile 10 :

Hamburger1Hamburger2

Ne prêtez pas attention à mes données, c’est juste un mock sur un projet qui vient à peine de démarrer pour montrer l’implémentation du composant 😉

Ce projet a été créé par TommasoScalici sur GitHub, vous pouvez le retrouver sur ce lien. Il est sous licence MIT, et est encore maintenu (dernier commit il y a 26 jours à l’heure où j’écris ces lignes).

Il se base sur un principe simple : le menu hamburger est en fait une page conteneur, qui va contenir notre page principale. C’est cette page principale qui va se charger de tout le reste.

Documentation

L’avantage avec ce composant, c’est que la page d’accueil sur GitHub résume bien les possibilités et l’utilisation du composant, ce qu’on ne retrouve pas forcément chez tous les composants. Donc je ne vais pas m’étendre sur l’implémentation en XAML du composant avec l’architecture du composant, car cela reste assez simple avec la documentation (MenuListItem, Header, Footer, etc.).

Je vais juste revenir sur le point Conteneur/Contenu, au cas où vous êtes amenés à changer vos noms de page/namespaces.

La page conteneur, qui va contenir notre composant AppShell, doit être définie dans le fichier App.xaml.cs, dans la méthode OnLaunched.


if (e.PrelaunchActivated == false)
{
if (rootFrame.Content == null)
{
// Quand la pile de navigation n'est pas restaurée, accédez à la première page,
// puis configurez la nouvelle page en transmettant les informations requises en tant que
// paramètre
rootFrame.Navigate(typeof(MenuPage), e.Arguments);
}
// Vérifiez que la fenêtre actuelle est active
Window.Current.Activate();
}

Ensuite, dans cette page (dans mon cas MenuPage), vous pouvez passer votre page fille dans le constructeur :


///
/// Une page vide peut être utilisée seule ou constituer une page de destination au sein d'un frame.
///
public sealed partial class MenuPage : Page
{
public MenuPage()
{
this.InitializeComponent();
TommasoScalici.AppShell.AppShell.Current.AppFrame.Navigate(typeof(MainPage));
}
}

Et le tour est joué!

Pour résumer, les avantages que j’ai trouvé à ce plugin est :

  • l’implémentation rapide et assez logique
  • le respect des thèmes (dark/light)
  • la disponibilité sur NuGet
  • la documentation ni trop conséquence ni trop succinte
  • le projet toujours actif
  • la licence, non contraignante

En espérant vous avoir aidé et fait connaître un plugin assez sympathique, bon développement!

 

 

Publicités

Pattern Singleton

Le pattern Singleton est l’un des design patterns les plus connus. Il permet de faire en sorte qu’une classse ne possède qu’une seule instance via une méthode de classe retournant celle-ci.

Ce pattern est utilisé pour des classes n’ayant besoin qu’une seule instance, ou encore pour éviter d’utiliser des variables globales dans l’application, ce qui ne fait pas très POO 😉 .

Il est vraiment simple à appréhender niveau code : dans notre classe statique Singleton, on a une propriété privée _instance qui ne peut être initialisée que via une méthode GetInstance(). De plus, le constructeur de Singleton est privé, afin que seule la méthode GetInstance puisse y accéder.


public class Singleton
{
private static Singleton _instance = null;
private Singleton()
{
// Initialisation des propriétés de la classe Singleton
}
public static Singleton GetInstance()
{
if (_instance == null)
_instance = new Singleton();
return _instance;
}
}

Vous savez désormais implémenter le pattern Singleton. Bon développement!

Créer ses Data Annotation Validator personnalisées (ASP.NET MVC)

En ASP.NET MVC, quand vous mettez en place une validation de formulaire, il est très utile d’utiliser les Data Annotation Validator sur le modèle pour vous épargner toute la logique de test de code. Le Framework .NET en comprend nativement plusieurs :

  • Range : permet la validation si la valeur de la propriété testée est dans une certaine tranche
  • RegularExpression : permet la validation si la valeur de la propriété testée respecte la RegEx fournie
  • Required : Comme son nom l’indique, permet d’indiquer une propriété comme requise
  • StringLength : Dans le cadre d’une propriété de type String, spécifie la longueur maximum de chaîne.
  • DataType : permet la validation si la valeur de la propriété testée repecte le type spécifiée (DataType.Date par exemple)
  • Validation : classe de base pour tous les attributs de validation.

Pour plus de détails sur le fonctionnement des Data Annotation Validators, vous pouvez consulter ce lien : ASP.NET

Ce qui nous intéresse ici n’est pas de revoir toutes ces bases, mais d’envisager une chose : si on doit faire une validation qui n’est pas prévue par le Framework .NET, comme par exemple une validation qui dépend d’une autre propriété? On devra passer par nos propres Data Annotation Validators, ce qui peut devenir très intéressant.

Présentation avec un cas concret : Date maximum

Tout le monde a connu au moins une fois dans sa vie de développeur ce scénario : lors d’une saisie de fourchette de date, la date maximum ne peut pas être inférieure ou égale à la date minimum. Ce sera la base de mon premier Custom Validator.


///
/// Spécifie qu'une valeur de champ correspondant à une date ne peut pas dépasser une autre valeur de champ correspondant à une date
///
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
public class MaxValueDateTimeAttribute : ValidationAttribute
{
}

Via ce petit bout de code, vous pouvez remarquez que j’ai créé une classe de type MaxValueDateTimeAttribute. Prenez l’habitude de mettre Attribute en suffixe : lors de l’utilisation du Validator dans les ViewModels, vous verrez que le suffixe Attribute est supprimée.

Deux autres choses sont à noter :

  • L’utilisation d’AttributeUsage. Ici, on spécifie que ce Validator sera valable sur les propriétés, les champs et les paramètres. AllowMultiple permet de dire si on peut spécifier plusieurs fois le même attribut sur un unique champ, ce qui ne sera pas notre cas ici.
  • L’implémentation de ValidationAttribute : tous vos Validators doivent implémenter cette classe (pour information, c’est justement le Validation cité précédemment!)

Pour l’usage de notre Validator, nous avons besoin de faire référence à la date minimum. Pas de souci, on ajoute une propriété qu’on va initialiser via le constructeur !


private String _minDateTimeProperty;


CheckMinValueDateTimeAttribute(String minDateTimeProperty)
{
_minDateTimeProperty = minDateTimeProperty;
}

En implémentant le Validator dans le ViewModel, on voit que le constructeur fait bien son boulot :
 CustomValidator
Et voici l’implémentation côté ViewModel :


[Display(Name = "Date minimum")]
public DateTime DateMin { get; set; }


[CheckMinValueDateTime("DateMin", ErrorMessage = "La date maximum est inférieure à la date minimum")]
[Display(Name = "Date maximum")]
public DateTime DateMax { get; set; }

Maintenant, on a notre contrôle lié aux deux dates, et implémentée dans la date correspondante. Il est temps d’implémenter la logique permettant de dire si la règle est valide ou non. Dans mon cas, elle est valide si la date max est supérieure ou égale à la date min. Il est temps de surcharger la méthode IsValid !


protected override ValidationResult IsValid(Object value, ValidationContext validationContext)
{
PropertyInfo propertyInfo = validationContext.ObjectType.GetProperty(this._minDateTimeProperty);
Object minValuePropertyValue = propertyInfo.GetGetMethod().Invoke(validationContext.ObjectInstance, null);
Boolean isMinValueEmpty = (minValuePropertyValue == null);
if (!isMinValueEmpty)
{
if (!(minValuePropertyValue is DateTime))
throw new NotSupportedException(" La propriété de comparaison doit être de type DateTime");
DateTime minValue = (DateTime)minValuePropertyValue;
DateTime currentValue = (DateTime)value;
if (currentValue < minValue)
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
return ValidationResult.Success;
}

Rien de bien compliqué je pense : les deux premières lignes me permettent de récupérer la propriété DateMin à partir du nom et de récupérer la valeur via sa méthode publique. Ensuite je fais ma comparaison, et si ça échoue, je retourne un objet ValidationResult correspondant à l’erreur, sinon je retourne ValidationResult.Success.
Cependant, si vous analysez bien, vous avez dû remarquer quelque chose…
Si vous placez un point d’arrêt sur votre code, vous verrez que votre éditeur y passera après un aller/retour serveur, et donc avant les autres propriétés natives. C’est parce qu’il s’agit de l’Unobtrusive Javascript, et qu’on ne l’a pas mis en place dans notre classe. Je vais sûrement en faire un tutoriel plus tard ou compléter celui ci, en attendant vous pouvez lire ce ticket de blog très intéressant : Blog de Brad Wilson.
En résumé dans ce ticket vous avez appris à créer un Validator, notamment celui concernant les dates, bien que perfectible : on peut gérer un booléen pour dire si la date max doit être supérieure ou supérieure ou égale, la validation des types peut se faire bien avant via d’autres Validators… Les possibilités sont immenses.
Bon développement!

Erreur 403 sur les Bundles CSS avec ASP.NET MVC sous Azure

Ayant récemment créé un site mettant en avant mon parcours professionnel, j’ai décidé de l’héberger sur la plateforme Azure. Cependant, bien que mon projet soit opérationnel en Debug et en Release en local, une fois déployé il n’y avait tout simplement aucune mise en forme. En fouillant sur Internet, j’ai constaté que je ne suis pas un cas isolé, et que ce problème date de plusieurs années…

En regardant le profiler Edge, je me suis rendu compte que le problème venait du bundle. Après recherche spécifique sur mon moteur de recherche, la solution était là: si votre bundle CSS correspond à un dossier physique de votre projet, IIS va vous renvoyer tout simplement une erreur 403 : étrange, quand on nous incite à déposer des feuilles de style dans un dossier spécifique, et quand on est dans une architecture full Microsoft…

Pour éviter ce désagrément, il suffit juste de remplacer le nom du bundle à sa création :

bundles.Add(new StyleBundle(« ~/Styles/css »).Include(
« ~/Content/css/bootstrap.css »,
« ~/Content/css/bootstrap-responsive.css »,
« ~/Content/css/site.css »));

ainsi qu’à son appel:

@Styles.Render(« ~/Styles/css »)

C’est ce genre d’erreur qui peut nous prendre des heures à corriger, et heureusement qu’il y a des blogueurs pour relayer l’information. Je tiens ma source de TheBeardDeveloper, qui m’a évité beaucoup de tracas!

==, Equals et ReferenceEquals, quelle différence ?

Quand on commence à développer, on se demande parfois comment comparer efficacement deux types en C# : ==, Equals ou encore ReferenceEquals, il existe plusieurs manière de comparer deux éléments, donc comment faire la différence ?

Avant d’aborder cet article, il faudrait savoir la différence entre les types valeurs (int, decimal, enums, etc.) et références (string, etc.). Je ferais peut être un article plus tard là dessus, mais pour l’instant d’autres développeurs plus compétents le font mieux que moi 🙂

Comme vous le savez, tout objet en C# dérive de la classe Object. A partir de ceci, deux méthodes seront à notre disposition :

A partir de là, nous avons déjà une base pour travailler.

ReferenceEquals

Si nous lisons la documentation, nous pouvons déjà voir que ReferenceEquals a pour signature public static bool, et que le développeur ne peut pas la réécrire dans des classes dérivées.

  • Si le type testé est de type valeur, alors on peut avoir des comportements bizarres (si on fait un test de référence sur la même valeur, on aura toujours false).
  • Si le type testé est string, alors on va tester la référence, mais on peut avoir un phénomène qui se produit appelé le  String Interning.
String chaine1 = "test";
String chaine2 = "test";
String.ReferenceEquals(chaine1, chaine2);

On aura … true. Comme les string sont immutable (donc impossible de modifier un string sans créer implicitement un autre string en mémoire), une optimisation est faite à l’exécution lors de la création des string : si une même valeur de string existe en mémoire, on va pointer vers l’adresse mémoire de cette chaine plutôt qu’en créer une autre, dans un but d’optimisation.

  • Si le type testé est un autre type référence, on teste la référence.

Par curiosité, si on veut voir l’intérieur de la méthode, voilà ce qu’on a :

public class Object {
    public static bool ReferenceEquals (Object objA, Object objB) {
        return objA == objB;
    }
}

Equals

Equals a en revanche pour signature public virtual bool : les développeurs peuvent réécrire la méthode Equals dans des classes dérivées.

  • Si le type testé est de type valeur, la méthode Equals testera l’égalité de valeur, et donc la méthode Equals prendra tout son sens.
  • Si le type testé est string, alors là aussi on va tester sa valeur.
  • Si le type testé est de type référence, la méthode Equals testera l’égalité de référence, et sera donc équivalente à ReferenceEquals, sauf si la méthode a été réécrite (c’est le cas de la classe String par exemple)

Pareil que précédemment, le code :

public class Object {
    public virtual Boolean Equals(Object obj) {
        if(this == obj) return true;
        return false;
    }
}

Donc en gros, ReferenceEquals et Object sont intimement lié à l’opérateur ==… Mais que fait-il exactement? Nous allons le découvrir ensemble!

==

Tout d’abord, un petit passage dans la documentation!

Maintenant, parlons de cet opérateur, qui est un peu particulier. dans le sens où il prend le type de l’instance à gauche de l’opérateur, donc faites attention à l’ordre de vos tests!

De plus, deux choses à savoir :

  • Si l’instance actuelle est de type valeur ou est un string (type référence), l’opérateur == testera l’égalité de valeur
  • Si l’instance actuelle est de type référence autre que string, l’opérateur testera l’égalité de référence, à défaut d’être réécrit par le développeur.

Ce qui veut dire que si on a ce code :

String chaine1 = "test";
Object chaine4 = chaine1;
chaine4 == chaine1;

chaine4 étant de type Object, on utilisera la méthode Object.ReferenceEquals plutôt que String.Equals : On aura une comparaison de référence, et non de valeur. D’ailleurs Visual Studio nous prévient (en tout cas dans la version 2010 que j’utilise au travail), en disant « Possibilité d’une comparaison de références involontaire ; pour obtenir une comparaison de valeurs, effectuez un cast de la partie gauche en type ‘string' ».

D’ailleurs, un point important pendant mes recherches avec ce flux Stack Overflow, et notamment la réponse de BlueMonkMN : le type String réécrit à la fois la méthode Equals et l’opérateur ==, pour qu’il agisse tel qu’un type valeur.

 

Concernant les sources de mes recherches, je vous invite bien sûr à consulter le flux Stack Overflow que je vous ai cité, ainsi que les autres qui traitent sur ce sujet, et à consulter le livre CLR by C# de Jeffrey Richter (ça deviendra vite une habitude), qui est une vraie Bible dorénavant pour moi. Mais aussi et plus simplement à faire vos tests par vous même! C’est le meilleur moyen de découvrir le comportement du Framework.

En espérant vous avoir aiguillé sur le choix de vos futurs tests, à bientôt!

Inauguration du blog

Cela faisait longtemps que je l’avais créé, mais le manque de temps dû au travail professionnel et à la veille technologique (et des raisons personnelles) ont fait que je l’ai laissé à l’abandon, mais j’inaugure enfin ce blog!

J’y mettrais quelques astuces que je trouverais par ci par là sur Internet, dans des livres ou encore de ma propre expérience personnelle. Si un de mes articles peut éviter une heure de galère a un développeur français, je serais déjà comblé!

Bonne lecture!