Astuces DotNet (Sébastien Courtois)

15/04/2010

[Silverlight] Sortie de Silverlight 4 RTW

Filed under: .NET, Débutant, Silverlight, Silverlight 3, Silverlight 4 — Étiquettes : , , , , — sebastiencourtois @ 23:40

Ca y est : Silverlight 4 est disponible à la page suivante : http://www.silverlight.net/getstarted/

Beaucoup de nouveautés (drag/drop, impression,clic droit …) dont certains ont déja été décrit sur ce blog :

D’autres posts sur le sujets arriveront bientôt.

EDIT : Silverlight 4 Tools NE FONCTIONNE PAS SUR VS 2008…. Il faut obligatoirement VS 2010 pour développer en SL4… De plus les outils de développement sont en RC pour le moment car il fallait que Silverlight 4 soit complètement terminé pour finaliser les outils de développement (ils ont du finir sur le fil SL4 :)).

Publicités

25/01/2010

[Silverlight 4] Supprimer le context menu “Silverlight” lors d’un clic droit

Filed under: Débutant, Silverlight 4, XAML — Étiquettes : , , , , , — sebastiencourtois @ 22:41

Silverlight 4 apporte une nouveauté très demandée : La gestion du clic droit. Le problème est que, par défaut, le clic droit s’accompagne d’un menu contextuel “Silverlight” un peu énervant. Toutefois, il y a une manière de s’affranchir de celui-ci.

L’évènement MouseRightButtonDown est un RoutedEvent qui, lorsqu’il est déclenché, est transmis de contrôle enfant à contrôle parent (ainsi de suite jusqu’au contrôle racine). Or, s’il arrive en haut de l’arbre visuel, il affiche par défaut le menu contextuel “Silverlight”.

1°)Une solution simple est d’indiquer que l’évènement a été géré (e.Handled = true) dans la callback de l’événement.

<UserControl x:Class="RightClickHandled.MainPage"
    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"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <Grid x:Name="LayoutRoot" Background="White">
        <Rectangle Fill="Red" Width="300" Height="200" MouseRightButtonDown="Rectangle_MouseRightButtonDown"></Rectangle>
    </Grid>
</UserControl>
public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void Rectangle_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
        }
    }

Le problème de cette méthode est qu’il faut le mettre sur chacune des callbacks de MouseRightButtonDown. De plus, cela arrête la remontée de l’évenement MouseRightClickDown aux contrôles parent qui doivent peut être y réagir.

2°) Utilisation d’un behavior : Etant donné mon dernier post, je ne pouvais m’empêcher de voir si un behavior peut régler la solution…. et c’est le cas. Pour ceux qui ne connaissent pas les behaviors, vous pouvez vous référez à cette introduction sur les behaviors).

    public class EraseSilverlightContextMenuBehavior : Behavior<UIElement>
    {
        protected override void OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.MouseRightButtonDown += new MouseButtonEventHandler(AssociatedObject_MouseRightButtonDown);
        }

        void AssociatedObject_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            this.AssociatedObject.MouseRightButtonDown -= new MouseButtonEventHandler(AssociatedObject_MouseRightButtonDown);
        }
    }

Après on associé le behavior au contrôle et le tour est joué.

<UserControl x:Class="RightClickHandled.MainPage"
    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:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:local="clr-namespace:RightClickHandled"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <Grid x:Name="LayoutRoot" Background="White">
        <Rectangle Fill="Red" Width="300" Height="200">
            <i:Interaction.Behaviors>
                <local:EraseSilverlightContextMenuBehavior />
            </i:Interaction.Behaviors>
        </Rectangle>
    </Grid>
</UserControl>

Le soucis avec cette méthode est qu’il faut appliquer le behavior à tous les contrôles ce qui peut devenir lourd.

3°)La solution la plus générique serait de s’abonner à l’événement MouseRightButtonDown du RootVisual contenu dans le App.xaml.cs afin de bloquer l’événement juste afin sa sortie de l’arbre visuel.

private void Application_Startup(object sender, StartupEventArgs e)
{
    this.RootVisual = new MainPage();
    this.RootVisual.MouseRightButtonDown += (sender2, args) => { args.Handled = true; };
}

Ainsi tous les contrôles de l’arbre visuel peuvent avoir accès à l’évènement sans contrainte. Plus besoin de l’implémenter sur chacun des contrôles car cela est géré au niveau de la racine de l’arbre.

Si vous avez des méthodes plus smart pour faire cela, n’hésitez pas à me les indiquer :).

18/03/2009

Silverlight 3 Beta SDK Released ….

Filed under: Silverlight — Étiquettes : , , , — sebastiencourtois @ 16:06

Le Mix 2009 se tient actuellement à Las Vegas et, pour commencer cette série de conférence, Scott Guthrie a annoncé la sortie du SDK de Silverlight 3 Beta 1.

D’après des sites que j’ai pu lire les SDK et même la MSDN serait déja disponible :).

Au programme de Silverlight 3 : … pas beaucoup d’informations. Apparemment accélération graphique 3D ( mais pas comme WPF… juste pour des petits effets 3D type carrousels), Pixel Shader, Haute Définition pour les vidéos … je pense aussi des nouveaux contrôles et autres.

Les liens que j’ai trouvé sur le sujet (contient les liens pour télécharger la bête) :

http://arstechnica.com/microsoft/news/2009/03/silverlight-3-related-bits-start-to-arrive-early.ars

http://www.neowin.net/news/main/09/03/18/microsofts-silverlight-3-beta-sdks-released

Je n’ai pas encore eu le temps d’y toucher mais je m’y mets dès ce soir 🙂 …

[Silverlight 2] Les converters typés

Filed under: Débutant, Intermediaire, Silverlight, WPF — Étiquettes : , , , — sebastiencourtois @ 15:46

 

Ceux qui ont déjà touchés à Silverlight 2 ou à WPF ont été amené à utilisé les converters. En travaillant, je me suis aperçu qu’une partie du code que j’écrivais dans un converter était principalement de la vérification de type d’entrée et de sortie. La cause : Les converters ne sont pas typés. Cela est, je pense, une fonctionnalité voulue par Microsoft afin de rendre ce système le plus flexible possible. Toutefois, j’aime bien les choses typés et ce principe me dérangeait d’autant que, la plupart du temps, je voulais un type d’entrée spécifique et un type de sortie spécifique.

Il existe un attribut en WPF pour “gérer” ce problème : ValueConversionAttribute. Toutefois, l’utilisation de cet attribut est de l’ordre informatif et il ne réalise aucune vérification. Le texte qui suit est donc valable pour WPF et Silverlight.

Partons d’un converter classique : Le BoolToVisibilityConverter

Le principe de ce converter est de fournir un booléen en entrée qui va définir un System.Windows.Visibility en sortie.

Voici le code du converter classique : 

Blog7-1

Comme vous pouvez le remarquer, 14 lignes de code pour écrire ce converter et 8 ne concerne pas la conversion en elle même mais plus les vérifications de types. J’ai ainsi factoriser ce code dans une classe abstraite générique afin n’avoir plus QUE de la conversion de type au sein de mes converters.

Code de la classe générique abstraite mère :  (VType représente le type d’entrée. TType représente le type de sortie.)

Blog7-2

Par héritage, on obtient le BoolToVisibiltyConverter suivant :

Blog7-3

Le développeur n’a plus qu’à remplir les méthodes abstraites héritées de TypedConverter. Ces méthode seront correctement typés (que ce soit dans leur paramètres et dans leur valeur de retour). De plus, la vérification de type est garanti par la classe mère. Au sein de BoolToVisibilityConverter, on ne retrouve que le code de conversion.

Certains pourront dire que ce code ne sert à rien car il fait perdre la flexibilité de Silverlight 2 (qui est un de ses grands atouts). Même si cela est vrai, 90 % des cas d’utilisations des converters se réalise avec un type d’entrée bien défini et un type de sortie bien défini. Autant essayé de gagner de la lisibilité dans le code sur ces cas là. Pour des cas nécessitant plus de flexibilité, rien n’empêche d’utiliser le bon vieux IValueConverter.

EDIT 18/03/09 : Suite à des tests, j’ai découvert un petit bug sur le code du TypedConverter. En effet, l’héritage au niveau du TargetType n’était pas pris en compte.

Exemple : Si on crée un TypedConverter<object,object> (i.e un converter standard), et qu’on lui fournit un targetType de Visibility, on obtient l’exception : “le type de sortie doit être …”. En effet, Visibility n’est pas object. Toutefois, vu que Visibility hérite de object, on aimerait pouvoir passer ce type de donnée pour qu’il soit valider “par héritage”. Or le test recherche une différence entre deux System.Type sans regarder la hiérarchie des classes. J’ai donc modifié le code du TypedConverter :

public abstract class TypedConverter<VType,TType>  : IValueConverter
{
	public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
	{
		//Vérification du type d'entrée
		if (!(value is VType))
			throw new InvalidOperationException("La paramètre d'entrée doit être de type "+ typeof(VType));
		//Vérification du type de sortie
		if(!this.IsTargetType(targetType,typeof(TType)))
			throw new InvalidOperationException("La type de sortie doit être de type " + typeof(TType));
		return this.Convert((VType)value, culture);
	}

	public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
	{
		//Vérification du type d'entrée
		if (!(value is TType))
			throw new InvalidOperationException("La paramètre d'entrée doit être de type " + typeof(VType));
		//Vérification du type de sortie
		if (!this.IsTargetType(targetType, typeof(VType)))
			throw new InvalidOperationException("La type de sortie doit être de type " + typeof(TType));
		return this.ConvertBack((TType)value, culture);
	}

	protected abstract TType Convert(VType p, CultureInfo culture);
	protected abstract VType ConvertBack(TType p, CultureInfo culture);

	//Méthode recherchant un type correspondant dans la hierarchie des classes
	private bool IsTargetType(Type targetType, Type type)
	{
		while(targetType != null)
		{
			if (targetType == type)
				return true;
			targetType = targetType.BaseType;
		}
		return false;
	}
}

L’héritage est ainsi gérer par l’utilisation de la méthode IsTargetType qui remonte l’arborescence des classes de targetType jusqu’à trouver une classe correspondant au type demandé. Si ce n’est pas le cas, une exception est lancée.

11/03/2009

Erreur 404 lors d’un Debug d’un projet ASP.NET en utilisant “ASP.NET Development Server” sur localhost pour Vista

Filed under: Hors Catégorie, Intermediaire — Étiquettes : , , , , , , , , , — sebastiencourtois @ 12:10

Bon, le titre est un peu long pour un post aussi court mais il s’agit des mots clés que j’ai mis dans Google pour résoudre un bug qui m’empêchait de bosser depuis quelques temps (d’où le peu de post sur ce site récemment).

Lorsque je travaillais sur un projet ASP.NET (Silverlight ou autres), je me prenais systématiquement une page d’erreur 404 au lancement du débogage. J’étais sûr à 99.99 % que cela ne venait pas de mes projets car je les utilisait depuis plusieurs mois sans problème.

Après de longues recherches (car très peu de posts parlent de ce problème), j’ai trouvé le blog de Accidental Technologist et sur celui de Information for Technology qui indiquent que cela vient d’un bug/problème sous Vista avec les adresses IPv6 pour localhost.

La Solution :

Modifier le fichier hosts dans le répertoire C:\Windows\System32\drivers\etc.

Remplacer

::1             localhost

par

:::1             localhost  (si vous êtes en IPv6)

127.0.0.1             localhost  (si vous êtes en IPv4)

 

Cette solution m’a permis de visualiser ma page sous IE.

L’explication :

Je n’ai pas trouvé d’explication exacte quant à ce problème mais je vais vous donner ma reflexion :

en IPv4, l’adresse localhost est 127.0.0.1.

Avec l’arrivée de l’IPv6, on obtient l’adresse localhost suivante : 0:0:0:0:0:0:0:1

Or d’après la norme IpV6, on peut supprimer les 0 quand il y en a : 0:0:0:0:0:0:0:1 => :::::::1  (7 caractères ‘:’ et un caractère ‘1’)

Toujours d’après cette norme. Si plusieurs ‘:’ se suivent, on peut les remplacer par un seul au début et un seul à la fin donc  :::::::1 => ::1

Lorsque l’on tape dans IE, la chaine suivante : http://[::1]/ .On retombe bien sur la page localhost.

Deux questions me viennent donc à l’esprit :

1°) Pourquoi rajouter un ‘:’ dans le fichier host (Sachant que d’après la norme :  ::1 == :::1 == 0:0:0:0:0:0:0:1 et que ::1 est bien localhost dans la norme) ?

2°) Que s’est-il passé sur mon ordinateur pour que ce problème apparaisse alors que mes projets fonctionnaient correctement à l’origine (Problème détecté la première fois le 10/03/09) ?

Si vous arrivez à répondre à l’une de ces questions, n’hésitez pas à poster en commentaire :). Je continue à chercher de mon coté et je mettrais à jour ce post si je trouve.

EDIT 11/03/09 12h27 : Apparemment pas le seul dans ce cas, car j’ai reçu ce mail  il y a quelques minutes (venant un Microsoft Student Partner dont je vais taire le nom 🙂 ) :  “je voulais savoir si tu avais déjà eu des problèmes avec Cassini, parce que là il ne veut plus m’afficher aucune page que ce soit sur un site ASP.Net MVC, ou ASP.Net classique.”.

EDIT 11/03/09 15h00 : Il semble qu’une mise à jour de Windows Defender aurait modifier le fichier hosts entrainant des bugs sur les sites ‘localhost’

04/03/2009

[Silverlight 2] Insertion d’un Tooltip dans l’en-tête du Datagrid

Filed under: Intermediaire, Silverlight, XAML — Étiquettes : , , , , — sebastiencourtois @ 15:26

Arrivé avec la RTW de Silverlight 2, le contrôle Datagrid permet d’afficher des données de façon structurées sous la forme d’une grille. Sa simplicité d’utilisation et sa personnalisation assez complète en XAML en font un objet indispensable pour toutes les interfaces Silverlight métiers (i.e autres que du jeu ou de la vidéo :)). Toutefois, cette personnalisation peut s’avérer complexe lorsqu’on souhaite modifier certaines parties qui n’ont pas été conçu pour être modifié … facilement.

J’ai une grille de données avec des en-têtes de colonnes se nommant “Header 1”,”Header 2” …. Pour chaque en-tête, je souhaite avoir un message lorsque je passe ma souris dessus.

Blog1

(Si vous êtes pressé, la solution se trouve à la fin du post)

Processus de recherche / Explications :

Je décide de rajouter ToolTipService.Tooltip=”test”  dans la balise d’un des DataGridTextColumn car cette propriété m’est proposée par l’IntelliSense.

Blog3-2J’obtiens une exception à l’exécution m’indiquant que le ToolTipService.Tooltip est un attribut inconnu pour l’élément DataGridTextColumn. (Texte exact : "XAML Parse Exception : Unknown attribute ToolTipService.ToolTip on element DataGridTextColumn.“)

ToolTipService est une propriété statique dans la classe FrameworkElement.

Blog3-5 Blog3-4

En analysant les hiérarchies ci dessus, on s’aperçoit que DataGridTextColumn ne dépend pas de FrameworkElement. Il faut donc utiliser une classe dérivant de FrameworkElement afin d’avoir accès à cette propriété. L’idée est donc de remplacer le texte de l’en-tête par un FrameworkElement de son choix (dans notre cas, un TextBlock) et de renseigner sa propriété ToolTipService.Tooltip.

Lorsqu’on regarde les propriétés disponibles pour les en-têtes pour le DataGridTextColumn, on s’aperçoit que les choix sont limités

Blog3-3La propriété Header ne prend que des chaines de caractères permettant de changer le titre. La propriété HeaderStyle permet de définir un Style pour l’en-tête. Pas de HeaderTemplate ou de propriétés de Template pour l’en-tête de colonne directement accessible par DataGridTextColumn.

L’astuce suivante a été trouvé par une collègue de travail: Simon Ferquel (MVP Silverlight).

En analysant la classe DataGridColumn dans Reflector, on peut voir que une propriété HeaderCell de visibilité internal. Cette propriété est de type DataGridColumnHeader dans le namespace System.Windows.Controls.Primitives. DataGridColumnHeader étant un ContentControl, on peut utiliser son ContentTemplate pour mettre tous les FrameworkElement que l’on souhaite :). Ne pouvant pas passer directement par la propriété HeaderCell à cause de sa visibilité, on utilise la propriété HeaderStyle pour faire la modification de l’en-tête.

Solution :

On utilise la propriété HeaderStyle de DataGridTextColumn pour redéfinir son HeaderCell. En XAML, cela donne :

Blog3-8Attention à ne pas oublier la ligne d’ajout du namespace au début du fichier XAML :

Blog3-9

Il est noté que cette exemple fonctionne avec toutes les classes héritant de DataGridColumn et pas uniquement pour DataGridTextColumn. 

Résultat final (le curseur de la souris a disparu lors de la capture) : Blog3-10

02/03/2009

Premier post de ce blog

Filed under: Hors Catégorie — Étiquettes : , , , , , , — sebastiencourtois @ 22:59

Bonjour à tous,

Je vais commencer par me présenter :

Je m’appelle Sébastien Courtois.

Je suis Consultant / Chef de projet .NET chez Winwise à Paris.Je fait partie du pôle RIDA (Rich Internet and Desktop Application). Pour résumer, je travaille régulièrement en Winforms, ASP.NET, Silverlight, WPF, ASP.NET MVC …

Afin de rendre ce blog unique, je vais essayer de publier un article/astuce par jour. Je ne sais pas si je tiendrais le rythme :).

Les articles et astuces seront principalement des cas pratiques tirés de ma propre expérience ou des expériences/questions d’autres personnes avec qui j’ai l’habitude de travailler (ils se reconnaitront surement assez vite). Ce ne seront souvent pas des exemples très poussés mais plus des petits problèmes quotidiens qui nous font perdre un temps précieux en projet.

En espérant que ce blog vous aidera et vous plaira. N’hésitez pas à m’envoyer des retours sur les erreurs ou les améliorations possibles (il y en aura surement :)).

Créez un site Web ou un blog gratuitement sur WordPress.com.

%d blogueurs aiment cette page :