Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Cyril Sansus

WPF, Interfaces Utilisateurs et .NET
[WindowPhone7] Premiers pas

Hop voici les premiers pas avec les outils de développement pour Windows Phone 7.

Premier changement suite à l’installation des outils : les type de projets pour la plateforme Windows Phone 7. Les projets se découpent en deux groupes :

  1. Les projets Silverlight
  2. Les projets XNA

image

Du coté du Designer de Visual Studio 2010 RC : un émulateur, du XMAL et tout plein de contrôles avec les styles par défaut.

image 

Les développeurs Silverlight et WPF ne seront pas perdus car on retrouve bon nombre des outils (Style, Layout, Controles….).

Je vous recommande vivement de jeter un petit coup d’œil au UI Design and Interaction Guide.

En résumé, un énorme travail sur cette nouvelle plateforme.

Windows Mobile 7 – Silverlight + XNA !

L’actualité Windows Mobile est très active depuis la Mobile World Confress 2010 à Barcelone. (Contrairement à mes posts depuis le début de l’année)

Tout commence le 15 février avec l’annonce de Steeve Ballmer de Windows Phone 7 Series :

“Today, I’m proud to introduce Windows Phone 7 Series, the next generation of Windows Phones.”

“In a crowded market filled with phones that look the same and do the same things, I challenged the team to deliver a different kind of mobile experience. Windows Phone 7 Series marks a turning point toward phones that truly reflect the speed of people’s lives and their need to connect to other people and all kinds of seamless experiences.”

Hier, Microsoft a dévoilé quelques détails sur la plateforme applicative qui reposera sur Silverlight et XNA et qui ne sera pas compatible avec la version 6.5.

Plus de détails sur le blog de Pierre Cauchois.

Prochaine étape : le MIX pour avoir les outils de développement en main.

Et si vous souhaitez avoir des informations supplémentaires sur la prochaine plateforme mobile, rendez-vous à la 4ème édition de la Bewise Day Conférence à Toulouse.

C’est l’évènement gratuit à ne pas rater si on veut découvrir les nouvelles technologies Microsoft ou poser des tas de questions à des experts ou aux Microsoftees.

A bientôt !

Interfaces professionnelles avec Windows Mobile (Part 2)

Dans la première partie, nous avons vu un aperçu des problématiques et des limitations de Windows Mobile lors la création de formulaires.

Dans cette seconde partie, nous allons examiner les outils mis à notre disposition afin de créer des formulaires Windows Mobile et voir les avantages et les inconvénients de chacun.

A noter que les notions présentées ici sont valables en Windows Forms.

Designer de Visual Studio

Tout d’abord parlons de Visual Studio, et plus exactement de son éditeur de formulaire. Plutôt agréable et simple, très proche de l’éditeur de Windows Forms, il permet de créer très rapidement des formulaires. Son principal intérêt est qu’il permet d’avoir un aperçu des formulaire (voir la figure 1). Autre caractéristique tout aussi intéressante, vous pouvez modifier la propriété FormFactor des fenêtres afin de visualiser le résultat sur d’autres émulateurs.

Capture  Figure 1 : Aperçu d’un formulaire dans Visual Studio.

Pour le reste, il suffit de faire glisser un contrôle depuis la Toolbox et de le positionner à l’endroit souhaité.

AutoScaleMode

Un des problématiques dans la création d’interface est la gestion des différentes résolutions : 320x240, 640*480 (VGA), 497x480 (QVGA), WVGA, etc.

Pourquoi est-ce un problème ? Tout simplement parce qu’un écran VGA est 2 fois plus grand qu’un écran classique. Pour qu’une interface garde le même aspect, il faudrait donc multiplier toutes les dimensions par 2. 

Heureusement les fenêtres réalisent automatiquement ce changement d’échelle lorsque la propriété AutoScaleMode de la fenêtre est positionnée à Dpi (valeur par défaut).

En résumé le problème de la résolution est considérablement réduit grâce à cette propriété et toutes les interfaces que vous réaliserez resterons identiques quelque soit la résolution du mobile.

Nous verrons plus tard que dans le cadre du développement de contrôle personnalisé que la notion d’AutoScale doit être prise en compte.

Positionnement

Si on devait simplifier, la conception d’une interface graphique revient à positionner et dimensionner des contrôles dans une fenêtre. Pour cela, vous avez plusieurs possibilités :

  • Soit faire du positionnement manuel
  • Soit faire du positionnement “automatique”

Pour illustrer mes propos j’utiliserais un formulaire très simple composé de trois éléments :

  • Un Label positionné en haut du formulaire
  • Un bouton positionné en bas du formulaire et centré horizontalement
  • Une ListBox qui occupera l’espace restant dans la partie centrale
Positionnement manuel

Le positionnement manuel consiste à définir une position (Location) et une taille (Size) fixe. Le code pour le formulaire d’exemple ressemble à ceci :

this.label1.Location = new System.Drawing.Point(3, 0);
this.label1.Size = new System.Drawing.Size(234, 17);
 
this.listBox1.Location = new System.Drawing.Point(4, 21);
this.listBox1.Size = new System.Drawing.Size(233, 212);
 
this.button1.Location = new System.Drawing.Point(84, 245);
this.button1.Size = new System.Drawing.Size(72, 20);

Voici le résultat sur l’émulateur “Classic” en version portrait (à gauche), paysage (au centre) et sur l’émulateur “Square” (à droite).

image image image

Figure 2 : Positionnement manuel

Plusieurs problèmes se posent :

  • Les marges (semi-automatiques avec le designer de VS) sont hétérogènes donnant une impression d’interfaces non finalisées.
  • Le mode paysage ne fonctionne pas correctement
  • Toutes les résolutions ne sont pas prise en charge

Les problèmes d’orientation d’écran et de résolutions sont parfaitement normaux étant donné que la position et la taille sont fixes.

Il existe un moyen simple pour contourner ce problème : les ancres (Anchor).

Les ancres peuvent être définies sur les 4 cotés (gauche, droite, bas, bouton) des contrôles à l’aide de la propriété Anchor des contrôles. Elles permettent de “coller” les côtés d’un contrôle aux côtés de son parent. Exemple, un bouton avec une ancre en bas à droite restera coller en bas à droite quelque soit la résolution ou l’orientation.

Si on modifie sensiblement notre exemple en ajoutant des ancres sur les trois contrôles :

this.label1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
this.listBox1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
this.button1.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;

On obtient le résultat suivant :

image image image

Figure 3 : Positionnement manuel avec ancrage

Cette fois-ci, le résultat est satisfaisant.

D’une manière générale on utilise des ancres lorsqu’on fait du positionnement manuel.

Attention toutefois ce mode de positionnement à une limite : si un élément de l’interface change dynamiquement de taille, les autres éléments ne suivront pas ! De plus la gestion des marge avec Visual Studio est une véritable prise de tête, il faut généralement repasser derrière le Designer pour avoir quelque chose de plus propre.

Positionnement automatique

A la différence du positionnement manuel, le positionnement automatique ne vous permet de définir ni la position ni la taille des contrôles : c’est le système qui les calcule automatiquement.

Le positionnement automatique se fait en utilisant la propriété Dock. Le “docking” permet :

  • D’empiler votre contrôles soit à droite, à gauche, en bas ou en haut
  • ou de définir que votre prend tout l’espace disponible

La figure ci-dessous montre un exemple avec 5 contrôles qui utilisent les différents modes de docking.

image Figure 4 : Différents modes de Dock

Donc si on “dock” une bouton en haut (figure 4):

  • Sa position est (0, 0) soit en haut à gauche.
  • Sa largeur est la largeur de l’écran et n’est pas modifiable
  • Sa hauteur sera la hauteur que vous lui avez fixé.

Fonctionnalité intéressante : lorsqu’on dock plusieurs contrôles en haut (figure 5), les contrôles s’empilent les uns en dessous des autres.

image

Figure 5 : Plusieurs boutons dockés en haut

Voici le code et le résultat de l’interface de test avec du positionnement automatique.

this.label1.Dock = System.Windows.Forms.DockStyle.Top;
this.listBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.button1.Dock = System.Windows.Forms.DockStyle.Bottom;

image image image

Figure 6 : Positionnement automatique

Le résultat est correct sur les différentes résolutions et orientations d’écrans. Cependant on remarques plusieurs défauts :

  • Le bouton prend toute la largeur de l’écran
  • Les marges sont incorrectes : les contrôles sont collés au bord. 
  • Un espacement excessif est mis entre le la liste et le bouton.

Il est possible de contourner le problème du bouton en utilisant un Panel :

  • Le Panel est docké en bas
  • Le bouton est positionné dans le Panel
  • On utilise du positionnement manuel au niveau du bouton

A noter que le positionnement automatique a un avantage majeur : il prend dynamiquement en compte le changement de la taille des contrôles. Autrement dit, si un contrôle est redimensionné, la position des autres contrôles sera automatiquement ajustée.

Conclusion

Nous venons de voir qu’avec le positionnement manuel, l’utilisation d’ancre et quelques retouches on obtient un très bon résultat. Mais la modification de ce type d’interface est complexe.

A l’inverse avec le positionnement automatique il est très simple d’ajouter ou modifier des contrôles : l’affichage se mettra automatiquement à jour. Malheureusement le système calculant tout automatiquement, on n’obtient pas toujours le résultat attendu.

Généralement si j’en restais là, je vous conseillerais d’utiliser à la fois le positionnement manuel et automatique.

Mais je ne vais pas m’arrêter là car ce mécanisme n’est pas satisfaisant. L’objectif ici est de créer des interfaces professionnelles, homogènes, intelligentes, simple à créer, simple à manipuler et maintenables.

Rendez-vous donc dans la prochaine partie où nous verrons comment faire mieux en prenant le meilleurs des deux types de positionnements que nous venons de voir (oui il y aura du code !).

D’ici quelques jours, vous pourrez retrouver cet article (et bien d’autres) sur le site de Bewise.

[Windows Mobile] Afficher une fenêtre lors d’une exception non gérée

Personne n’est à l’abri d’une exception non gérée, c’est à dire une exception que vous n’avez pas “catché” et qui fait planter méchamment votre application. Heureusement il est possible de détecter ce type de plantage et d’afficher une fenêtre.

Pour récupérer les exceptions non gérées, vous devez utiliser l’évènement UnhandledException comme suivant (d’ailleurs cela devrait être la première instruction de la plupart des applications .NET) :

AppDomain.CurrentDomain.UnhandledException += 
                                    CurrentDomain_UnhandledException;

Ensuite, il est possible d’y afficher une fenêtre afin d’informer l’utilisateur qu’une erreur est survenue.

static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
    using (ErrorForm form = new ErrorForm(e.ExceptionObject as Exception))
    {
        form.ShowDialog();
    }
}

Problème le code-ci dessous ne vous affichera pas la fenêtre !? En effet la méthode ShowDialog retournera directement DialogResult.None.

En fait, l’état plutôt instable de l’application lors d’une exception non gérée fait que votre fenêtre peut recevoir des messages erronées depuis la boucle de messages Win32.

Pour palier ce problème vous pouvez utiliser la méthode Application.DoEvents() comme le montre le code suivant :

static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
    Application.DoEvents();
 
    using (ErrorForm form = new ErrorForm(e.ExceptionObject as Exception))
    {
        form.ShowDialog();
    }
}

Et voilà : ca marche !

Layout pour Windows Mobile (Part 1)

Windows Mobile est, contrairement à ce que l’on pourrait croire, une plateforme ultra complète pour le développement mobile : Compact Framework, office, téléphonie, connectivité, Bluetooth, GPS, notifications, gesture, Web Service, Threading …

Malgré tout cela, Windows Mobile se traine une API plutôt vieillotte concernant l’interface graphique. L’un des points faibles qui va nous intéresser est le layouting, c’est à dire le positionnement, le dimensionnement et la création de formulaires mobiles pour créer de vraies applications métiers.

En effet, la création d’un formulaire Windows Mobile n’est pas évidente si on souhaite obtenir une interface modulable qui s’adapte à la fois à la résolution, à l’orientation de l’écran ainsi qu’au contenu des contrôles.

Un problème majeur qu’on rencontre également en Windows Forms à la différence que le Framework .NET est plus complet sur ce point (FlowLayoutPanel, TableLayoutPanel, AutoSize, GDI+ …).

Bref : Windows Mobile n’offre pas vraiment de solution “toute prête” pour positionner et dimensionner les éléments d’une interface. De ce fait, on abouti souvent à des interfaces peu homogènes et qui ne fonctionnent que pour une résolution donnée (je ne parle même pas de la rotation d’écran).

Une des principales lacunes des contrôles Windows Mobile est qu’ils ne sont pas capables d’adapter leur taille en fonction de leur contenu. L’exemple le plus flagrant est le contrôle Label qui ne possède pas de propriété AutoSize : vous devez définir des dimensions fixes. Et si par malheur le texte vient à change en cours d’exécution et qu’il dépasse la taille du Label, le texte sera tronqué.

Les figures ci-dessous illustrent cette problématique. A gauche , on peut voir un label avec un texte suffisamment court pour qu’il rentre en largeur. A droite, le même label mais pour lequel j’ai dû positionner un texte plus long : on ne peut tout simplement pas voir la fin du texte.

1 2

Si certains se disent “trop simple ! Un petit coup de MeasureString et le tour est joué”, sachez que le Compact Framework ne permet pas de calculer la taille d’un texte avec des contraintes en largeur :p

Toutes ces problématiques ont des solutions et je vous propose de les découvrir ensemble dans cette série de posts. La prochaine fois sera (je pense) consacrée aux outils que propose le Compact Framework afin de créer vos formulaires.

La boite de dialogue PrintDialog ne veut pas s’afficher !?

Si un jour vous utilisez la boite de dialogue PrintDialog, positionnez la propriété UseExDialog à True histoire d’éviter de perdre du temps.

En fait, dans la plupart des cas cela n’aura pas d’incidence. Par contre si vous êtes sur Windows 7 en 64 bits, votre boite de dialogue ne s’ouvrira pas et retournera directement DialogResult.Cancel.

Comme l’indique l’MSDN et plusieurs commentaires, la valeur par défaut aurait dû être True mais en fait elle est positionnée à False.

[Tips] RIA Services Class Library : le RiaContext n’est pas généré

La Microsoft .NET RIA Services July 2009 Preview apporte un nouveau template de projet : .NET RIA Services Class Library. Ce template génère 2 projets :

  • Une librairie de classe .NET dans lequel vous allez pouvoir mettre tous vos domaines
  • Une librairie de classe Silverlight dans laquelle les contextes sont générés

Avec la précédente version, il n’était pas possible d’activer les RIA Services au niveau d’une librairie de classe. Conséquence : tous les domaines étaient forcement dans le projet Web : pas forcement terrible comme découpage en terme de réutilisabilité.

Désormais cette lacune est comblée et il est possible de faire un vrai découpage.

Bref, voilà une fonctionnalité intéressante mais qui pose deux problèmes :

  1. la classe RiaContext n’est pas générée au niveau de la librairie Silverlight.
  2. lors  de l’authentification on se prend une vilaine exception :
    • DomaineContextType is null or invalid

Concernant le premier point, il faut créer manuellement la classe RiaContext dans votre application Silverlight. Plutôt logique si on part du principe que le contexte est lié à l’application. Voici le code anciennement généré que vous pouvez mettre dans votre application Silverlight :

public sealed partial class RiaContext : System.Windows.Ria.RiaContextBase
{
 
    #region Extensibility Method Definitions
 
    /// <summary>
    /// This method is invoked from the constructor once initialization is complete and
    /// can be used for further object setup.
    /// </summary>
    partial void OnCreated();
 
    #endregion
 
 
    /// <summary>
    /// Initializes a new instance of the RiaContext class.
    /// </summary>
    public RiaContext()
    {
        this.OnCreated();
    }
 
    /// <summary>
    /// Gets the context that is registered as a lifetime object with the current application.
    /// </summary>
    /// <exception cref="InvalidOperationException"> is thrown if there is no current application,
    /// no contexts have been added, or more than one context has been added.
    /// </exception>
    /// <seealso cref="Application.ApplicationLifetimeObjects"/>
    public new static RiaContext Current
    {
        get
        {
            return ((RiaContext)(System.Windows.Ria.RiaContextBase.Current));
        }
    }
 
    /// <summary>
    /// Gets a user representing the authenticated identity.
    /// </summary>
    public new User User
    {
        get
        {
            return ((User)(base.User));
        }
    }
}

Pour le deuxième problème, il faut modifier votre fichier App.xmal afin de lui fournie le service d’authentification qui se trouve désormais dans un autre projet ! Voici le code XMAL pour faire cela :

<Application.ApplicationLifetimeObjects>
    <app:RiaContext>
        <app:RiaContext.Authentication>
            <appsvc:FormsAuthentication DomainContextType="MyProjet.Web.AuthenticationContext, MyProjet.Services, Version=1.0.0.0"/>
        </app:RiaContext.Authentication>
    </app:RiaContext>
</Application.ApplicationLifetimeObjects>

Et voilà !

[Silverlight] Impossible d’installer RIA Services !?

Petite surprise durant l’installation de RIA Services. Je télécharge l’install de RIA Services July 2009 Preview (au préalable j’avais installé les pré-requis). Et blam ! L’installeur me dit que je n’avais pas installer le SDK Beta 3 ?

En fait j’avais bien installé le SDK mais il apparaissait en version française dans la liste des programmes installés.

J’ai donc re-télécharger l’install de Silverlight™ 3 Tools for Visual Studio 2008 SP1 en US, et hop, l’installation des RIA Services fonctionne correctement.

[WPF] Thumb … la suite !

Comme promis, voici un exemple plus concret de l’utilité du contrôle Thumb.

Voici comment en 20 minutes et à l’aide de 2 Thumbs, on peut déplacer et redimensionner des contrôles très simplement.

Edit : suite à une remarque judicieuse, je vous met même un petit GIF animé ! ThumbPart2

Le code source est extrêmement simple :

private void Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
    this.SetValue (Canvas.LeftProperty, (double)this.GetValue(Canvas.LeftProperty) + e.HorizontalChange);
    this.SetValue(Canvas.TopProperty, (double)this.GetValue(Canvas.TopProperty) + e.VerticalChange);
}
 
private void resizeThumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
    double width = this.ActualWidth + e.HorizontalChange;
    double height = this.ActualHeight + e.VerticalChange;
 
    if (width <= 0)
        width = 1;
 
    if (height <= 0)
        height = 1;
 
    this.Width = width;
    this.Height = height;
}

Hop, je vous laisse télécharger le code source (oui … j’ai passé les 20 minutes sous Blend)

Enjoy !

Télécharger le code source

[WPF] D&#233;placer des Windows sans bordure

WPF offre la possibilité de masquer la bordure et la barre de titre. Parfait pour créer des fenêtres arrondies, rondes, etc. Mais attention sans barre de titre, il n’est plus possible de déplacer une fenêtre !! “Don’t panic”, il existe un contrôle très sympas en WPF qui va nous aider : le Thumb.

Obtenir une fenêtre ronde en WPF

Pour créer une fenêtre ronde en WPF, il y a deux choses à faire. Premièrement il faut modifier deux propriétés de la fenêtre afin de masquer la barre de titre. Les propriétés en question sont : AllowsTransparency et WindowsStyle.

Deuxièmement, il faut modifier le Template de base de la fenêtre en remplaçant la bordure par défaut par une ellipse. On peut réaliser tout ceci via le style (version très épurée) de la fenêtre :

<Window.Style>
    <Style TargetType="{x:Type Window}">
        <Setter Property="AllowsTransparency" Value="True" />
        <Setter Property="WindowStyle" Value="None" />
        <Setter Property="Background" Value="Black" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Window}">
                    <Grid>
                        <Ellipse Fill="{TemplateBinding Background}" 
                                 Stroke="{TemplateBinding BorderBrush}" 
                                 StrokeThickness="{TemplateBinding BorderThickness}" />
                        <ContentPresenter />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Style>
 
On obtient ainsi une “jolie” fenêtre ronde mais il n’est pas possible de la déplacer (A noter que Alt+F4 permet de fermer la fenêtre).
Déplacer la fenêtre

La solution la plus simple (merci Lionel) est d’ajouter un élément quelconque et de se brancher sur l’évènement MouseLeftButtonDown. Ensuite il suffit d’utiliser la méthode DragMove de la fenêtre … et hop magie !

Le code XAML :

<Grid>
       <Rectangle Width="50" Height="50" Fill="White" 
                MouseLeftButtonDown="Rectangle_MouseLeftButtonDown"/>
</Grid>

Le code C# :

private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    DragMove();
}

Autre possibilité, utiliser le controle Thumb.

Le contrôle Thumb est un contrôle prévu pour les opérations de déplacement (Drag&Drop par exemple). Il permet de s’abstraire de la gestion de la souris (capture et calcul du delta de déplacement) et fournit directement un évènement DragDelta qui est levé à chaque fois que vous faites du drag au niveau du Thumb … bon là je suis pas clair, mieux vaut le code.

Voici dons le code XAML et CS qui permettra de mettre en place le Thumb :

<Grid>
      <Thumb Width="50" Height="50" DragDelta="Thumb_DragDelta" />
</Grid>

private void Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
    this.Left += e.HorizontalChange;
    this.Top += e.VerticalChange;
}

Hop, vous obtenez une magnifique fenêtre ronde et déplaçable.

Thread ou ThreadPool ?

L'asynchronisme est quelque chose de complexe : la bonne technique (Thread, ThreadPool, ...), la synchronisation, la concurrence, etc. Il existe de nombreux ouvrages à ce sujet mais certaines règles très simples peuvent vous faciliter le travail.

La question qui aujourd’hui m’intéresse est : Thread ou ThreadPool ? Voici quelques règles qui pourront, peut être, vous aidez dans ce choix.

On préconise souvent d’utiliser directement un Thread (l’artillerie lourde) :

  • Lors de tâches très longues. L’exemple parfait est une boucle “infinie” qui attend les connexion d’un client sur une socket.
  • Pour avoir plus de contrôle sur le Thread : attente, destruction, affinité, priorité …

Pour le reste on passera toujours par des ThreadPool (soit 95% des cas) :

  • Pour des tâches courtes
  • Des opérations d’I/O

D’ailleurs dans le Framework on retrouve très fréquemment le ThreadPool :

  • Délégués asynchrones
  • BackgroundWorker
  • Méthodes Begin* et End*
  • La plupart des I/O

Autre point : les performances.

J’ai réalisé un test qui vise à mesurer le temps de création de 1000 tâches. Dans un premier cas cela se traduira par le démarrage de 1000 Thread, et dans second cas l’exécution de 1000 workitems.

// 1er cas : Thread
Thread thread = new Thread(DoWork);
thread.Start();

// 2nd cas : ThreadPool
ThreadPool.QueueUserWorkItem(new WaitCallback((state) =>
{
}));


Les résultats (En release sur un Duo Core 2.2Ghz) sont parlants :

  • 230 ms pour le premier cas.
  • 0 ms pour le second.

Cela s’explique par le fait que créer un Thread n’est pas anodin : cela consomme beaucoup de ressources et prend du temps.

Le ThreadPool prépare un ensemble de Threads prêt à être utilisés, donc pas de temps de création. De plus, dès qu’un Thread du pool a fini d’exécuter son WorkItem, il sera réutilisé par un autre WorkItem réduisant ainsi la consommation de ressources.

Enum.TryParse ?

Alors qu’on peut trouver int.TryParse, DateTime.TryParse dans le Framework .NET, la méthode Enum.TryParse n’existe pas.

La méthode intuitivement utilisée pour essayer de convertir une chaîne de caractères en une Enum est la suivante  :

   1: public static bool TryParse(String value, out T result)
   2: {
   3:     result = default(T);
   4:     try
   5:     {
   6:         result = (T) Enum.Parse(typeof(T), value, true);
   7:         return true;
   8:     }
   9:     catch
  10:     {
  11:         return false;
  12:     }
  13: }

L’inconvénient d’utiliser la méthode Enum.Parse lorsque la conversion n’est pas possible est que l’exécution est très très très lente ! L’exemple suivant met environ 2 secondes pour s’exécuter :

   1: for (int i = 0; i < 1000; i++)
   2: {
   3:     TryParse ("Hello !", out result);
   4: }

Tout ca pour dire, que cette méthode peut s’avérer inutilisable dans certains cas. En fait ce qui est lent dans cette méthode, c’est le simple fait de lever une exception pour dire que la conversation a échoué (lever une exception c’est mou et c’est pour cela que ça doit rester exceptionnel).

Pour contourner le problème il existe différentes méthodes que vous trouverez un peu partout sur la toile. Attention, sachez que Enum.Parse gère TOUS les cas figures :

  • Remplacement de certaines caractères spéciaux (+,-, _)
  • Gestion des Flags
  • Gestion de la case

Ceci n’est pas forcement vrai des méthodes que vous allez trouver ! Pour ma part, j’ai opté pour la solution simple qui ne gère même pas la case :

   1: public static bool TryParse(string valueToParse, out T returnValue)
   2: {
   3:     returnValue = default(T);
   4:     if (Enum.IsDefined(typeof(T), valueToParse))
   5:     {
   6:         returnValue = (T)Enum.Parse(typeof(T),valueToParse);
   7:         return true;
   8:     }
   9:     return false;
  10: }

A noter, que si je refais le précédent test cette méthode ne mettra que 1 milliseconde.

WPF and Silverlight Designer for Visual Studio 2010

Un nouvel espace dédié au designer de Visual Studio 2010 pour WPF et Silverlight vient d'ouvrir ses portes.

On pourra y trouver des resources (blog, articles, webcast) sur tout ce qui concerne WPF et Silverlight dans Visual Studio 2010.

Hop ! Ca se passe par là : http://windowsclient.net/wpfdesigner/

Posted: jeudi 28 mai 2009 09:40 par Vko | 0 commentaire(s)
Classé sous : ,
[WPF] Afficher l'utilisation CPU à l'aide d'une jauge

Voici une des démonstrations que j'avais présenté à la BDC 2008 afin de démystifier Blend. L'objectif était de transformer une barre de progression en jauge, tout ça en 10 minutes.

Pour réaliser cette démonstration, j'ai "simplement" créé un ControlTemplate avec Blend que j'ai ensuite appliquer à la barre de progression.

L'image ci-dessous présente la barre de progression avant et après :

jauge0 

Télécharger le code source

A noter que le format écrit n'est pas le meilleur format : un WebCast devrait arriver pour présenter la solution sous Blend. Mes explications ici seront assez expéditives :)

Visualiser l'utilisation du CPU

Pour rendre la barre de progression un peu plus dynamique, elle affiche l'utilisation du CPU. J'ai donc créé une DependencyProperty, nommée CpuUsage, au niveau de la fenêtre :

public int CpuUsage
{
    get { return (int)GetValue(CpuUsageProperty); }
    set { SetValue(CpuUsageProperty, value); }
}
 
public static readonly DependencyProperty CpuUsageProperty = DependencyProperty.Register("CpuUsage", typeof(int), typeof(SolutionWindow), new UIPropertyMetadata((int)0));

Et "bindée" cette propriété au niveau d'une ProgressBar :

<ProgressBar Value="{Binding Path=CpuUsage, ElementName=Window}" />

Il ne reste plus qu'à utiliser la classe PerformanceCounter pour récupérer le pourcentage d'utilisation du CPU, et d'un DispatcherTimer afin de mettre à jour la valeur de la propriété CpuUsage :

private void CreatePerformanceCounter()
{
    cpuCounter  = new PerformanceCounter();
    cpuCounter.CategoryName = "Processor";
    cpuCounter.CounterName = "% Processor Time";
    cpuCounter.InstanceName = "_Total";
 
    timer = new DispatcherTimer();
    timer.Tick += OnTimerTicker;
    timer.Interval = TimeSpan.FromMilliseconds(1000);
    timer.Start();
}
 
private void OnTimerTicker(Object sender, EventArgs e)
{
    this.CpuUsage = (int)cpuCounter.NextValue();
}

A ce stade, nous avons une barre de progression qui affiche l'utilisation du CPU.

Notez que dans la solution téléchargeable j'ai utilisé une animation afin de rendre le changement plus progressif et fluide.

Créer le Template

Le Template va permettre de tranformer la barre de progression en jauge, et notamment d'afficher la valeur de la ProgressBar sous la forme d'une aiguille qui tourne. La contrainte étant de pouvoir recréer ce Template en 5 minutes.

La première chose est de réfléchir à la structure graphique de la jauge, la figure ci-dessous montre le découpage de la jauge :

jauge

Dans cette jauge, il y a deux choses qui ne peuvent pas (enfin ci ... mais bon) être faites avec Blend :

  • Les graduations. Pour afficher les graduations, j'ai créé un petit contrôle qui affiche des rectangles à intervalles réguliers.
  • La conversation de l'utilisation du CPU exprimée en pourcentage en une valeur angulaire. Ceci sera fait par un Converter nommé PercentageConverter.

Vous pourrez retrouver ces deux éléments au niveau de la solution.

Pour le reste, il suffit d'ouvrir Blend, de créer un ControlTemplate vierge, et de superposer les différents éléments graphiques identifiables dans la figure précédentes à savoir :

  • Un effet chromé : une ellipse avec un RadialGradientBrush
  • Un fond noir : une ellipse avec un LineraGradientBrush
  • Les graduations : le contrôle de graduations
  • L'aiguille qui tournera : un rectangle
  • Le centre de l'aiguille : encore une ellipse
  • Et enfin le petit reflet : perso j'ai utilisé un Path

La subtilité de ce Template réside au niveau de l'aiguille qui doit :

  • Etre centrée au milieu de la jauge
  • Tourner à sa base en fonction de la propriété Value de la ProgressBar.

Pour résoudre la première problématique, on peut utiliser une grille avec deux lignes et positionnée l'aiguille dans la première ligne et centrée horizontalement au milieu (c'est bien plus simple à comprendre sous Blend) :

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="0.5*"/>
        <RowDefinition Height="0.5*"/>
    </Grid.RowDefinitions>
    <Rectangle Width="3" HorizontalAlignment="Center" />
</Grid>

Pour le problème de rotation de l'aiguille, il suffit d'utiliser une RotateTransform sur le rectangle. On n'oublie pas de modifier la propriété RenderTransformOrigin afin que la rotation se fasse à la base du rectangle :

<Rectangle RenderTransformOrigin="0.5,1" Width="3" HorizontalAlignment="Center" >
    <Rectangle.RenderTransform>
        <TransformGroup>
            <RotateTransform>
                <RotateTransform.Angle>
                    <Binding Path="Value" RelativeSource="{RelativeSource TemplatedParent}">
                        <Binding.Converter>
                            <converters:PercentageConverter/>
                        </Binding.Converter>
                    </Binding>
                </RotateTransform.Angle>
            </RotateTransform>
        </TransformGroup>
    </Rectangle.RenderTransform>
</Rectangle>

Enfin, on utilise une expression de Binding. Cette expression permet de lier la valeur de la propriété Value de la ProgressBar (qui représente le pourcentage CPU) à l'angle de la rotation de l'aiguille.

On n'utilise le PercentageConverter décrit plus haut afin de transformer la valeur d'utilisation CPU en valeur angulaire.

Enjoy !!

[WPF] HyperLink + Document + Copier/Coller = NotSupportedException

La classe FlowDocument vous permet d'afficher n'importe quel type de contenu : texte, image, lien hypertexte, etc., extrêmement pratique ! Toutefois, elle présente un léger problème lorsqu'on utilise un HyperLink.

Exemple : le code ci-dessous permet d'afficher le texte "Voici un lien" :

   1: <FlowDocument>
   2:     <Paragraph>
   3:         <Run>Voici un</Run>
   4:         <Hyperlink Command="local:Window1.MaCommande">lien</Hyperlink>
   5:     </Paragraph>
   6: </FlowDocument>
   1: public partial class Window1 : Window
   2: {
   3:     public static readonly RoutedCommand MaCommande = new RoutedCommand("MaCommande", typeof(Window1));
   4:     ...
   5: }

La particularité de ce code est la présence d'une commande au niveau de l'HyperLink.

Si vous exécutez ce code, que vous sélectionnez tout le texte et faites un Copier (ou un Drag), vous allez avoir une belle "NotSupportedException" : 'CommandConverter' is unable to convert 'System.Windows.Input.RoutedCommand' to 'System.String'.

Comme le souligne le texte de l'Exception, WPF n'arrive pas à convertir une Command en String. En utilisant Reflector, on peut s'apercevoir que le code de la méthode ConvertTo de la classe CommandConverter n'autorise que la conversion des commandes fournies par WPF !

La solution la plus simple pour contourner le problème est donc d'utiliser une des commandes de WPF:

  • Dans la classe System.Windows.Input.ApplicationCommands
  • Ou bien System.Windows.Input.NavigationCommands

Exemple :

   1: <Hyperlink Command="input:NavigationCommande.GoToPage">lien</Hyperlink>

D'autres solutions existent, comme recréér la classe HyperLink ou ne pas utiliser les Commandes, mais j'avoue que j'aime bien la solution facile :p

Posted: mardi 10 mars 2009 20:11 par Vko | 0 commentaire(s)
Classé sous :
Performances avec WCF

Si comme beaucoup de gens vous vous posez encore la question "WCF est-il plus performant que Remoting (ou WSE) ?" - oui il y a des gens qui se posent encore la question - je vous conseille d'aller voir ce petit comparatif de l'MSDN :

http://msdn.microsoft.com/en-us/library/bb310550.aspx

Posted: vendredi 6 mars 2009 09:36 par Vko | 2 commentaire(s)
Classé sous :
Comment faire un screenshoot d'un contrôle WPF ?

Rien de plus simple en WPF, je pense que le code ci-dessous se passe de commentaire :

   1: private void Screenshoot(FrameworkElement element, String filename)
   2: {
   3:     RenderTargetBitmap targetBitmap = new RenderTargetBitmap((int)element.ActualWidth, 
   4:                                                              (int)element.ActualHeight, 
   5:                                                              96d, 
   6:                                                              96d, 
   7:                                                              PixelFormats.Default);
   8:  
   9:     targetBitmap.Render(element);
  10:  
  11:     JpegBitmapEncoder encoder = new JpegBitmapEncoder();
  12:     encoder.Frames.Add(BitmapFrame.Create(targetBitmap));
  13:  
  14:     using (FileStream stream = File.Open(filename, FileMode.Create))
  15:     {
  16:         encoder.Save(stream);
  17:     }
  18: }
[WPF] Supprimer le padding des cellules d'une ListView

Ce qu'il y a de bien avec WPF, c'est toutes ces petites choses qu'on trouve coder en dur.

Prenez par exemple cette ListView avec un joli rectangle rouge de 20*20

<ListView DataContext="{StaticResource ds}" ItemsSource="{Binding}"> <ListView.View> <GridView> <GridView.Columns> <GridViewColumn Width="20" Header=""> <GridViewColumn.CellTemplate> <DataTemplate> <Rectangle Width="20" Height="20" Fill="Red" /> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> ...

Si on exécute une telle ListView, on se rend compte que notre joli rectangle ne fait que 8 pixels de largeur !

Après avoir chercher dans tous les ControlTemplate où pouvait bien se cacher ce ?*ù!$ padding, j'ai démarré mon outil préféré : Reflector.

Et voila ce que j'y ai trouvé dans la classe GridViewRowPresenter :

_defalutCellMargin = new Thickness(6.0, 0.0, 6.0, 0.0);

Hop, je sors ma calculatrice : 8 + 6 + 6 = 20 ... tiens drôle de coïncidence !? Malheureusement le hasard n’y est pour rien, la valeur de padding est bel et bien fixée en dur dans le code.

Il n’y a aucun moyen de modifier cette valeur proprement, une solution pour contourner le problème est d’affecter une marge de (-6,0,-6,0) au CellTemplate de la colonne, et hop le tour est joué !

<DataTemplate>
     <Rectangle Margin="-6,0,-6,0" Width="20" Height="20" Fill="Red" />
</DataTemplate>
 
Posted: lundi 8 septembre 2008 21:40 par Vko | 0 commentaire(s)
Classé sous :
Plus de Messages « Page précédente


Les 10 derniers blogs postés

- Office 365: Nettoyage des versions de List Item avant migration depuis SharePoint On Premise vers SharePoint Online par Blog Technique de Romelard Fabrice le 08-08-2017, 15:36

- Office 365: Comment supprimer des éléments de liste SharePoint Online via PowerShell par Blog Technique de Romelard Fabrice le 07-26-2017, 17:09

- Nouveau blog http://bugshunter.net par Blog de Jérémy Jeanson le 07-01-2017, 16:56

- Office 365: Script PowerShell pour assigner des droits Full Control à un groupe défini par Blog Technique de Romelard Fabrice le 04-30-2017, 09:22

- SharePoint 20XX: Script PowerShell pour exporter en CSV toutes les listes d’une ferme pour auditer le contenu avant migration par Blog Technique de Romelard Fabrice le 03-28-2017, 17:53

- Les pièges de l’installation de Visual Studio 2017 par Blog de Jérémy Jeanson le 03-24-2017, 13:05

- UWP or not UWP sur Visual Studio 2015 ? par Blog de Jérémy Jeanson le 03-08-2017, 19:12

- Désinstallation de .net Core RC1 Update 1 ou SDK de Core 1 Preview 2 par Blog de Jérémy Jeanson le 03-07-2017, 19:29

- Office 365: Ajouter un utilisateur ou groupe dans la liste des Site collection Administrator d’un site SharePoint Online via PowerShell et CSOM par Blog Technique de Romelard Fabrice le 02-24-2017, 18:52

- Office 365: Comment créer une document library qui utilise les ContentTypeHub avec PowerShell et CSOM par Blog Technique de Romelard Fabrice le 02-22-2017, 17:06