Welcome to MSDN Blogs Sign in | Join | Help

Aurélien Norie

Un peu de dev n'a jamais fait de mal à personne...
Comment intégrer un contenu HTML dans une application Silverlight

Bonjour,

Le but de ce post est de montrer combien il est facile d’afficher du HTML dans une application Silverlight.

Silverlight ne proposant pas par défaut de contrôle HtmlViewer ou WebBrowser, nous allons devoir ruser un peu et faire ce qu’on appelle de l’Html Overlay.

L’idée est donc d’afficher un duo Div/iFrame par dessus l’application Silverlight, à l’endroit souhaité. l’iFrame se chargera d’afficher le contenu HTML souhaité.
Notez qu’afin que cela soit possible, il faut mettre la propriété Windowless de l’application Silverlight à True.

Nous allons donc créer un contrôle dans notre application Silverlight qui se chargera de créer et de positionner le div et l’iFrame sur l’application.

Le résultat obtenu est le suivant :

image

La page entière est une application Silverlight, qui semble nous afficher directement le contenu d’une page Web.

Pour arriver à ce résultat, voici les étapes à suivre :

  1. Créez un projet Silverlight 3, et prendre l’option où Visual Studio génère le site Web associé.
  2. Dans la page ASP.NET hébergeant l’application Silverlight, ajoutez l’attribut Windowless sur l’objet Silverlight et donnez lui la valeur True.
  3. Ajoutez une classe HtmlDisplay au projet Silverlight. Cette classe héritera de UserControl et pourra donc se placer directement dans le XAML de votre application Silverlight.
    Cet objet se chargera de créer les objets HTML div et iFrame, de les positionner  correctement sur la page, ainsi que de la navigation de l’iFrame.


    public class HtmlDisplay : ContentControl
    {
     
    private HtmlElement div;
     
    private HtmlElement iFrame;

     
    public HtmlDisplay()
     
    {
       
    this.Loaded += new RoutedEventHandler(HtmlDisplay_Loaded);
     

      void HtmlDisplay_Loaded(object sender, RoutedEventArgs e)
     
    {
       
    HtmlDocument htmlDocument = HtmlPage.Document;
       
    div = htmlDocument.CreateElement("div");
       
    div.Id = "monDiv";
       
    div.SetStyleAttribute("position", "absolute");
       
    div.SetStyleAttribute("height", this.Height.ToString() + "px");
       
    div.SetStyleAttribute("width", this.Width.ToString() + "px");
       
    GeneralTransform gt = this.TransformToVisual(Application.Current.RootVisual);
       
    Point position = gt.Transform(new Point(0, 0));
       
    div.SetStyleAttribute("left", position.X + "px");
       
    div.SetStyleAttribute("top", position.Y + "px");


       
    iFrame = htmlDocument.CreateElement("iframe");
       
    iFrame.Id = "monIFrame";
       
    iFrame.SetProperty("frameborder", "no");
       
    iFrame.SetStyleAttribute("height", this.Height.ToString() + "px");
       
    iFrame.SetStyleAttribute("width", this.Width.ToString() + "px");
       
    iFrame.SetStyleAttribute("position", "relative");


        div.AppendChild(iFrame);
       
    htmlDocument.Body.AppendChild(div);
     
    }

     
    public void Naviguer(string url)
     
    {
       
    if (iFrame != null)
       
    {
         
    iFrame.SetAttribute("src", url);
       
    }
     
    }
    }

  4.  


  5. Dans le XAML de la page Silverlight, ajoutez une référence à l’assembly de votre projet, et vous pourrez ensuite placer l’objet HtmlDisplay ainsi qu’une textbox et un bouton pour permettre de naviguer sur différentes pages.

    xmlns:my="clr-namespace:SilverlightApplication1"

    puis par exemple :

    <Canvas x:Name="LayoutRoot">
     
    <Canvas.Background>
       
    <LinearGradientBrush>
         
    <GradientStop Color="#FFD4D4D4" Offset="0"/>
         
    <GradientStop Color="#FF3B3B3B" Offset="1"/>
       
    </LinearGradientBrush>
     
    </Canvas.Background>

      <StackPanel  Orientation="Horizontal">
        <TextBox x:Name="Adresse" Text="http://www.bing.com"
                 Margin="10" Width="400" />
        <Button x:Name="Naviguer" Content="Go" Margin="10"
               
    Click="Naviguer_Click"  />
      </StackPanel>

      <my:HtmlDisplay x:Name="html" Canvas.Top="50"
                     
    Canvas.Left="10"
    Height="700"
                     
    Width="800" />
    </Canvas>
  6. Dans le code C# de votre application Silverlight, ajoutez le code pour permettre la navigation :

    private void Naviguer_Click(object sender, RoutedEventArgs e)
    {
     
    html.Naviguer(Adresse.Text.Trim());
    }

Vous trouverez les sources complètes de cet exemple ici.

A bientôt.
Aurélien

Modifications entre Silverlight 3 Beta et la version finale

Bonjour,

Comme vous le savez sûrement déjà, Silverlight 3 est désormais RTW depuis la semaine dernière.

Tous les liens pour installer les outils Visual Studio, le runtime, Blend 3, Silverlight Toolkit et “.NET RIA Services July 2009 Preview” sont recensés ici.

Une liste exhaustive de toutes les nouveautés (il y en a un paquet !) est disponible ici.

Si vous avez déjà commencé vos développements sur Silverlight 3 Beta, il se peut que certaines fonctionnalités soient cassées, à cause des “Breaking changes” entre la version Beta et la version finale de Silverlight 3.

 

Par exemple pour installer une application Silverlight sur la machine, il fallait faire en Silverlight 3 Beta :

Application.Current.Detach();

alors qu’en version finale, il faut faire :

Application.Current.Install();

 

La liste de tous ces “Breaking Changes” est disponible dans le document Changes.docx qui se trouve dans le SDK Silverlight :

C:\Program Files\Microsoft SDKs\Silverlight\v3.0\SDK Help\en-US\Changes.docx

Vous pourrez donc facilement migrer votre code en vous référant à ce document.

A bientôt,
Aurélien

Silverlight 3 Beta est disponible

Bonjour,

Depuis cette nuit, Silverlight 3 Beta est disponible en téléchargement !

Il s’agit d’une beta destinée aux développeurs afin qu’ils testent le nouvelles fonctionnalités.
Ce n’est donc pas une licence “go-live’.
Notez qu’il n’est pas possible d’avoir un environnement de développement avec Silverlight 2 et Silverlight 3 Beta installés ensemble. Privilégiez donc une VM pour cette nouvelle installation afin de garder votre environnement de développement Silverlight 2 pour vos développements en cours et la maintenance de vos applications en production.

Vous trouverez toutes les informations nécessaires pour installer le Runtime et le SDK, ainsi que les Outils Silverlight 3 Beta pour Visual Studio 2008, mais aussi Blend 3 Preview sur http://silverlight.net/GetStarted/silverlight3/default.aspx.
Vous y trouverez aussi des exemples de code et une liste des nouvelles fonctionnalités.

Alors amusez-vous bien avec Silverlight 3 !!

A bientôt,
Aurélien

Comment mettre de la transparence sur un menu contextuel Windows Forms

Bonjour,

Vous  avez créé une application qui se minimise dans le systray (à côté de l’horloge de Windows) et vous ajoutez à cette application un ContextMenuStrip afin d’afficher un menu contextuel.

Vous vous dites que ce serait bien de pouvoir rendre ce menu un peu plus attirant en y ajoutant de la transparence par exemple (c’est à la mode et ça plait bien :o)).

Dans la fenêtre des propriétés du contrôle ContextMenuStrip, aucune propriété ne laisse sous-entendre que cela est possible.
Toutefois, en creusant un peu sur la MSDN, vous apercevez que la propriété Opacity existe bel et bien sur le contrôle ContextMenuStrip.
Vous vous empressez alors de la modifier, mais à votre grand désespoir, vous vous rendez compte que si votre menu contextuel contient des sous-menus, alors les sous-menus ne sont pas transparents :

image

Il faut donc le faire avec du code natif en appelant directement l’API système SetLayeredWindowAttributes.

Voici un exemple de code qui parcourt le menu et met de la transparence sur tous les sous-menus :

[DllImport("user32.dll")]
static extern bool SetLayeredWindowAttributes(
  IntPtr hwnd,
 
uint crKey,
 
byte bAlpha,
 
uint dwFlags);

[DllImport("user32.dll", SetLastError = true)]
private static extern int SetWindowLong(
 
IntPtr hWnd,
 
int nIndex,
 
int dwNewLong);

[
DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(
 
IntPtr hWnd,
 
int nIndex);

private const int GWL_EXSTYLE = -20;
private const int WS_EX_LAYERED = 0x80000;
private const int LWA_ALPHA = 0x2;
double alpha = 0.7;

public Form1()
{
  InitializeComponent();
}


private void Form1_Load(object sender, EventArgs e)
{
  contextMenuStrip1.Opacity = alpha;
 
foreach (ToolStripMenuItem subMenuItem in contextMenuStrip1.Items)
  {
    setSubMenuTransparency(subMenuItem);
  }

}

private void setSubMenuTransparency(ToolStripMenuItem subMenuItem)
{
 
if (subMenuItem.HasDropDownItems)
  {
   
ToolStripItem tsi = subMenuItem.DropDownItems[0];
    SetWindowLong(
      tsi.Owner.Handle, 
      GWL_EXSTYLE, 
      GetWindowLong(tsi.Owner.Handle, GWL_EXSTYLE) ^ WS_EX_LAYERED);

    SetLayeredWindowAttributes(
      tsi.Owner.Handle, 
      0, 
      (
byte)(alpha * 255), 
      LWA_ALPHA);

   
foreach(ToolStripMenuItem smi in subMenuItem.DropDownItems)
      setSubMenuTransparency(smi);
}

 

Et voilà le résultat obtenu :

image

A bientôt,
Aurélien

Comment installer le SP2 du Framework 2.0 (suite et probablement fin…)

Bonjour,

Les choses ont encore évolué depuis mon dernier post puisque le package d’installation standalone est maintenant disponible ici.

Il n’est donc plus nécessaire d’installer les “bootstrappers” sur une machine où Visual Studio est installée !

A bientôt,
Aurélien

Comment installer le SP2 du Framework .NET 2.0

Bonjour,

Dans un article précédent intitulé “Le multi-targeting de Visual Studio et les Services Packs” je vous parlais de l’impossibilité d’installer seul le Service Pack 2 du Framework .NET 2.0.

Les choses ont évolué depuis et il devient possible d’installer ce Service Pack (et c’est le cas aussi pour le Service Pack 2 du Framework 3.0), grâce aux “.NET Frameworks 2.0 SP2 and 3.0 SP2 bootstrapper packages” téléchargeables ici.

Ces packages s’installeront sur les OS 32 et 64 bits, avant Windows Vista et les OS suivants pour lesquels l’installation du Framework 3.5 SP1 doit être privilégiée (d’ailleurs ces packages ne s’installeront pas sur ces OS).

Afin d’installer le Framework 2.0 SP2 sur un serveur Windows 2000 par exemple, la démarche est donc la suivante :

  • Sur une machine de développement où Visual Studio 2008 est installé:
    • Télécharger les “.NET Frameworks 2.0 SP2 and 3.0 SP2 bootstrapper packages”
    • Executer le package afin d’extraire les “bootstrapper”
  • Sur le serveur Windows 2000 (à jour au niveau des Services Packs bien évidemment, soit Service Pack 4) :
    • Installer le Rollup package KB891861 pour Windows 2000 SP4, qui contient un hotfix de sécurité sans lequel l’installation du Framework .NET 2.0 SP2 échouera.
    • S’assurer que Windows Installer 3.1 est installé, sinon l’installer à partir d’ici par exemple.
    • S’assurer que le Service Pack 1 du Framework .NET 2.0 est installé, sinon l’installer à partir d’ici.
    • Installer le Service Pack 2 du Framework .NET 2.0 qui se situe sur la machine de développement, à cet emplacement : C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bootstrapper\Packages\DotNetFx20SP2.

A bientôt,
Aurélien

Comment modifier dynamiquement la taille d’une application Silverlight

Bonjour,

Imaginons le scénario suivant : vous intégrez une application Silverlight dans un site web existant.
Pour cela, vous positionnez votre application Silverlight au sein d'une page web, vous indiquez la largeur et la hauteur de l'application.

Dans cette application Silverlight, vous ajoutez dynamiquement des contrôles, et vous vous rendez compte que les derniers contrôles ajoutés n'aparaissent pas dans votre application car elle n'est pas assez grande pour les afficher.

Le but du jeu est donc de modifier la taille du plugin Silverlight dynamiquement afin que tous les contrôles ajoutés soient visibles.

Prenons par exemple un StackPanel contenant un bouton, et ajoutons d'autres boutons à ce StackPanel dynamiquement lorsque l'on clique sur ce premier bouton.

<Canvas x:Name="LayoutRoot" >
   
<StackPanel x:Name="sp">
       
<Button Click="Button_Click" Content="Ajouter un controle" x:Name="btn" Height="50" />
   
</StackPanel>
</Canvas>

private void Button_Click(object sender, RoutedEventArgs e)
{
   
Button btnDyn = new Button();
    btnDyn.Content =
DateTime.Now.ToLongTimeString();
    btnDyn.Height = 50;
    sp.Children.Add(btnDyn);
}

La capture d'écran ci-dessous montre que ma pile de boutons est coupée car l'application Silverlight n'adapte pas sa taille automatiquement.

image

Dans cet exemple, j'ai positionné une taille fixe pour mon application, toutefois spécifier une hauteur de 100% ne résoudrait pas le problème car l'application prendrait la hauteur de la fenêtre, mais ne s'agrandirait pas toute seule lors de l'ajout des contrôles supplémentaires.

Ce que je souhaite, c'est que mon application Silverlight me permette de voir tous les contrôles, en m'affichant une barre de défilement sur le navigateur si besoin.

Je vais pouvoir dans le code managé modifier la taille du plugin Silverlight.
Pour cela, je calcule la taille de mon application a l'aide de la propriété ActualHeight de mon contrôle StackPanel que j'affecte ensuite de la manière suivante :

private void UpdatePluginHeight()
{
   
double height = sp.ActualHeight;

   
HtmlElement plugin = HtmlPage.Plugin;
   
HtmlElement host = plugin.Parent;
    plugin.SetStyleAttribute(
"height", height.ToString() + "px");
    host.SetStyleAttribute(
"height", height.ToString() + "px");
}

Notez le "px" qui est indispensable pour le bon fonctionnement de la fonctionnalité sous FireFox.

Bien évidemment, j'appelle cette méthode après avoir ajouté un contrôle dynamiquement, ce qui nous donne au final pour le gestionnaire d'événements de mon premier bouton :

private void Button_Click(object sender, RoutedEventArgs e)
{
   
Button btnDyn = new Button();
    btnDyn.Content =
DateTime.Now.ToLongTimeString();
    btnDyn.Height = 50;
    sp.Children.Add(btnDyn);

    UpdatePluginHeight();

}

Le résultat est le suivant, mon application Silverlight m'affiche tous les contrôles présents dans le StackPanel, même si sa hauteur est supérieure à la hauteur de la fenêtre (j'ai dans ce cas la barre de défilement verticale du navigateur qui me permet de voir le reste de l'application)

image

A bientôt,
Aurélien

Processeurs physiques, logiques et nombre de cœurs

Bonjour,

Historiquement, les ordinateurs étaient équipés d'un seul processeur, puis la notion de processeurs logiques est apparue avec ce qu'on appelait à l'époque l'hyper-threading (ou les processeurs multi-threadés), et nous voyons maintenant des ordinateurs équipés de deux cœurs, quatre cœurs et bien plus. 

Le but de ce rapide post est de vous présenter une méthode simplissime pour déterminer le nombre de processeurs physiques d’une machine, mais aussi le nombre de cœurs et le nombre de processeurs logiques.

Tout cela peut se faire via WMI sur Windows Vista et versions supérieures (mais aussi sur Windows 2003 avec le hotfix suivant installé : http://support.microsoft.com/kb/932370/en-us).

Le code vbscript suivant montre comment faire, notez que pour savoir si un processeur est hyper-threadé, il suffit de comparer le nombre de processeurs logiques et le nombre de cœurs :

strComputer = "."

 

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")

Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Processor")

 

WScript.Echo "Nombre de processeurs physiques : " & colItems.Count

For Each objItem in colItems

      Wscript.Echo "Processeur : " & objItem.Name

      Wscript.Echo "Nombre de processeurs logiques : " & objItem.NumberOfLogicalProcessors

      Wscript.Echo "Nombre de coeurs : " & objItem.NumberOfCores

 

      if objItem.NumberOfCores < objItem.NumberOfLogicalProcessors then

            WScript.Echo "Ce processeur est hyper-threadé"     

      else

            WScript.Echo "Ce processeur n'est pas hyper-threadé"

      end if

Next

A bientôt
Aurélien

Comment ajouter du contenu à un calendrier Silverlight

Bonjour,

Depuis quelques temps je cherchais à enrichir le contrôle Calendar de Silverlight afin de pouvoir afficher des données à partir d’une base.

Par défaut, ce contrôle ne sert qu'à proposer à un utilisateur de choisir une date sur un calendrier, il ne permet pas de parcourir la collection des jours du calendrier au runtime afin d'en modifier le contenu.

Partons sur un exemple concret : j'ai en mémoire un ensemble de rendez-vous (ici il s'agit d'objets créés en mémoire, dans un scénario réel on irait chercher ces données dans une base à l'aide d'un service), et je souhaite afficher un bouton pour chaque rendez-vous dans le calendrier.

Voici comment faire pour arriver à nos fins.

Pour commencer à définir l'aspect du contrôle Calendar, la première chose à faire est d'éditer le template du Calendar (à l'aide d'Expression Blend par exemple), puis de modifier le XAML pour changer le template du Calendar.

Notez que les espaces de noms suivants doivent être importés :
xmlns:System_Windows_Controls_Primitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls"
xmlns:basics="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"

Dans l'exemple suivant, j'ai modifié la couleur de fond afin de lui donner une couleur unie car la modification de la hauteur des cellules du calendrier au runtime ne me permettait pas de garder la couleur de fond prédéfinie par le contrôle (je vous laisse faire l’essai). J’ai laissé les autres valeurs par défaut…

<Style x:Key="CalendarStyle1" TargetType="basics:Calendar"> 
  <Setter Property="IsTabStop" Value="False"/> 
  <Setter Property="Background" Value="#FFFFFFFF" /> 
  <Setter Property="BorderBrush"> 
    <Setter.Value
      <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> 
        <GradientStop Color="#FFA3AEB9" Offset="0"/> 
        <GradientStop Color="#FF8399A9" Offset="0.375"/> 
        <GradientStop Color="#FF718597" Offset="0.375"/> 
        <GradientStop Color="#FF617584" Offset="1"/> 
      </LinearGradientBrush
    </Setter.Value
  </Setter
  <Setter Property="BorderThickness" Value="1"/> 
  <Setter Property="Template"> 
    <Setter.Value
      <ControlTemplate TargetType="basics:Calendar">
        <StackPanel HorizontalAlignment="Center" x:Name="Root">

          <System_Windows_Controls_Primitives:CalendarItem
            Background="{TemplateBinding Background}" 
            BorderBrush="{TemplateBinding BorderBrush}" 
            BorderThickness="{TemplateBinding BorderThickness}" 
            x:Name="CalendarItem"/> 
        </StackPanel
      </ControlTemplate
    </Setter.Value
  </Setter
</Style>

Jusqu'ici je n'ai fait que modifier la couleur de fond du calendrier, toutefois libre à vous de modifier le template du Calendar à votre guise.

Ce qui m'intéresse plus particulièrement ici, c'est de modifier l'objet CalendarDayButton afin d'y redéfinir le Template qui affichera le contenu de chaque jour (de type CalendarDayButton).
Voici comment je l'ai implémenté :

<Style x:Key="CalendarDayButtonStyle"
TargetType="System_Windows_Controls_Primitives:CalendarDayButton">
 
<Setter Property="Width" Value="80"/> 
  <Setter Property="Template"> 
    <Setter.Value>

      <ControlTemplate 
TargetType
="System_Windows_Controls_Primitives:CalendarDayButton"> 
              <Border BorderBrush="#FF598788"
                BorderThickness="1,1,1,1" 
                CornerRadius="2,2,2,2">
                  <Border.Background>
                    <LinearGradientBrush
            EndPoint
="0.5,1" 
            StartPoint
="0.5,0"> 
                          <GradientStop Color="#FFD3DEE8" Offset="0"/> 
             <GradientStop Color="#FFFFFFFF" Offset="1"/> 
          </LinearGradientBrush
         </Border.Background>
        
<StackPanel HorizontalAlignment="Center"> 
          
<System_Windows_Controls_Primitives:CalendarDayButton
             Loaded="CalendarDayButton_Loaded" 
            
Background="{TemplateBinding Background}" 
             BorderBrush="{TemplateBinding BorderBrush}" 
            
Content="{TemplateBinding Content}"
            
BorderThickness="{TemplateBinding BorderThickness}" 
            
x:Name="CalendarDayButton"/> 
         
</StackPanel
       
</Border>
     
</ControlTemplate
   
</Setter.Value
 
</Setter
</Style>

La première modification faite ici, c'est le changement de la propriété Width de l'objet CalendarDayButton
Le fait de modifier la largeur de chaque bouton me permet notamment de modifier la largeur globale du calendrier (vous aviez peut-être déjà remarqué que le fait de changer la propriété Width du Calendar lui-même ne fait rien ??).

Notez qu’après avoir modifié cette propriété, si vous passez l’affichage du calendrier en mode Month ou Decade, le calendrier retrouvera sa largeur d’origine. Pour éviter cela, vous pouvez modifier le style de l’objet CalendarButton pour changer la largeur des boutons.
Afin que la largeur globale du calendrier ne change pas, définissez la largeur d’un CalendarButton égale à : 7 x LargeurDuCalendarDayButton / 4, car en mode Month ou Decade, il n’y a que quatre boutons dans la largeur du calendrier (voir dans le code source de l’exemple téléchargeable en fin de ce post).

La modification principale, qui me permettra d'ajouter du contenu au contrôle se fait sur la définition du Template de l'objet CalendarDayButton.
Notez que j'ai modifié ce template afin d'y ajouter une bordure (objet Border sur lequel j'ai ajouté un dégradé en couleur de fond, ainsi que des angles arrondis), ainsi qu'un objet StackPanel à l'intérieur de cette bordure. Ce StackPanel me permettra d'empiler des objets sous le CalendarDayButton existant, qui se charge d'afficher le jour dans le calendrier.

La dernière modification à ce template est la suivante : je m'abonne à l'événement Loaded de l'objet CalendarDayButton.
Cet événement va être levé une fois par CalendarDayButton (soit 42 fois au total car le calendrier affiche 42 jours), et ne sera plus levé par la suite, même lorsque l'on change de mois.
L'idée est donc de stocker les références des 42 CalendarDayButton en mémoire, afin de pouvoir les manipuler par la suite.


private
List<CalendarDayButton> CalendarButtons;

//Création de la liste des CalendarDayButton 
private void CalendarDayButton_Loaded(object sender, RoutedEventArgs e) 

  CalendarDayButton cdb = sender as CalendarDayButton
  CalendarButtons.Add(cdb);

  //Le calendrier comporte 42 jours 
  //après que le dernier jour soit chargé, on remplit
  //le calendrier avec les données
  if (CalendarButtons.Count == 42) 
    RemplirCalendrier(
      
new DateTime(Calendar1.DisplayDate.Year,
       Calendar1.DisplayDate.Month, 1)); 
}

Une fois les contrôles CalendarDayButton stockés, nous allons pouvoir les manipuler pour afficher du contenu dedans.
Lors du chargement du dernier jour, on appelle la méthode RemplirCalendrier (définie plus loin dans cet article) en lui passant le premier jour du mois courant en paramètre afin d'afficher les rendez-vous du mois courant.

Avant toute autre chose, nous allons charger des données.
Pour cela, définissons une classe RDV :

    class RDV 
   
        public DateTime date { get; set; } 
        public string intitule { get; set; } 
    }

Puis dans l'événement Loaded du contrôle Silverlight, on crée une liste de RDV, et on définit quelques paramètres du calendrier (afin que la semaine commence un lundi par exemple) :


List<RDV> mesRDVs; 

private void LayoutRoot_Loaded(object sender, RoutedEventArgs e) 

  Calendar1.SelectionMode = CalendarSelectionMode.None; 
  Calendar1.FirstDayOfWeek = DayOfWeek.Monday; 
  CalendarButtons = new List<CalendarDayButton>(); 

  mesRDVs = new List<RDV
  {

    new RDV { date=new DateTime(2008, 11, 1), intitule="rdv1" }, 
    new RDV { date=new DateTime(2008, 11, 8), intitule="rdv2" }, 
    new RDV { date=new DateTime(2008, 11, 8), intitule="rdv3" }, 
    new RDV { date=new DateTime(2008, 11, 25), intitule="rdv4" },
   
new RDV { date=new DateTime(2008, 12, 7), intitule= "rdv5" },
   
new RDV { date=new DateTime(2008, 10, 28), intitule= "rdv6" }
  }; 
}

Maintenant que nous avons chargé des données il faut que l'on puisse savoir à quel jour du calendrier correspond chaque CalendarDayButton de notre liste lorsqu'on change de mois sur le calendrier.

//Changement de mois 
private void Calendar1_DisplayDateChanged(object sender, CalendarDateChangedEventArgs e) 
{

  RemplirCalendrier(Calendar1.DisplayDate); 
}

Ceci sera fait dans la méthode RemplirCalendrier ci-dessous.

private void RemplirCalendrier(DateTime PremierJourDuMoisCourant) 

  int compteur = 0; 
  StackPanel conteneur; 
  DateTime jourCourant; 
 
  int JourDu1erDuMois = (int)PremierJourDuMoisCourant.DayOfWeek; 

  //Cas du dimanche 
  if (JourDu1erDuMois == 0) JourDu1erDuMois = 7; 
  //Cas du lundi -> Si le Premier du mois est un lundi, 
  //alors il sera affiché sur la 2ème ligne du calendrier 
  if (JourDu1erDuMois == 1) JourDu1erDuMois = 8;

 
//Parcours de tous les jours

  foreach (CalendarDayButton cdb in CalendarButtons) 
  {
   
conteneur = cdb.Parent as StackPanel
   
jourCourant = PremierJourDuMoisCourant.AddDays(compteur).AddDays(1 - JourDu1erDuMois); 

   
int nbControles = conteneur.Children.Count; 

        //Suppression du contenu du jour
    //sauf du contrôle CalendarDayButton 
    for (int i = nbControles - 1; i > 0; i—) 
          conteneur.Children.RemoveAt(i); 

    //Sélection des RDV du jour courant 
        var query = from rdv in mesRDVs 
               
where rdv.date.Date == jourCourant 
                select new { rdv.intitule }; 

    //Ajout d'un contrôle Button
    //pour chaque RDV
                   
    foreach
(var rdv in query) 
    {
     
Button btn = new Button();
     
btn.Content = rdv.intitule;
     
conteneur.Children.Add(btn); 
    }

        compteur ++; 
 
}

}

La première étape est de calculer quel est le jour du 1er du mois courant.
A partir de cette information, on peut parcourir la collection de CalendarDayButton et définir la date que chaque CalendarDayButton représente.
Notez qu'il y a un un cas particulier pour le lundi (si je détermine que le lundi est le premier jour de la semaine) : si le premier du mois tombe un lundi, alors le premier du mois sera affiché sur la deuxième ligne du calendrier, afin que l'on puisse voir quelques jours du mois précédent sur le calendrier. Si vous définissez un autre jour comme étant le début de semaine, alors il faudra adapter un peu le code…

Il faut donc parcourir la liste de CalendarDayButton.
Pour chaque CalendarDayButton, je récupère son parent (qui est le StackPanel définit dans le template).
A partir de ce StackPanel, je supprime tous les contrôles enfants (sauf le CalendarDayButton lui-même que j'ai laissé à l'indice 0), afin de supprimer tous les RDV précédemment placés dans ce StackPanel.
Je définis le jour courant, puis je fais une requête sur ma collection de RDV afin de récupérer tous les RDV du jour courant.
Je boucle enfin sur le résultat obtenu, et j'ajoute pour chaque RDV un bouton (on pourrait imaginer autre chose) au StackPanel.
J'aurai aussi pu gérer l'événement click de chaque bouton afin d'afficher le détail du RDV lorsque l'utilisateur clique sur un RDV par exemple, mais je vous laisse le soin d'arranger tout cela comme vous le souhaitez...

Le résultat obtenu est le suivant :

 image

Si vous souhaitez changer le style général de votre calendrier, alors vous pouvez vous rendre sur le blog de Corrina Barber : http://blogs.msdn.com/corrinab/.

Vous pouvez télécharger le code source de cet exemple ici.

A bientôt,
Aurélien

 

       

Silverlight 2 est RTW !

Etant un adepte de Silverlight 2 depuis sa version Alpha (qui s'appelait Silverlight 1.1 Alpha à l'époque), j'ai le plaisir de vous annoncer que Silverlight 2 est RTW !

Si vous avez développé sur la version Beta 2 :

  • Désinstaller le Runtime Silverlight 2 Beta 2
  • Désinstaller le Silverlight SDK Beta 2
  • Désinstaller les Silverlight Tools Beta 2 for Visual Studio
  • Désinstaller Microsoft Expression Blend 2.5 June 2008 Preview (s'il était installé)
  • Désinstaller Deep Zoom Composer (s'il était installé)

Afin de développer sur Silverlight 2 RTW, vous devez :

Si vous désirez installer uniquement le runtime Silverlight 2, ça se passe ici.

Plus d'informations et de ressources sur http://silverlight.net/GetStarted et http://msdn.microsoft.com/fr-fr/silverlight/.

Bons développements sur Silverlight 2 !
Aurélien

Le multi-targeting de Visual Studio et les Services Packs

Bonjour,

Aujourd'hui je voudrais parler de Visual Studio 2008, du multi-targeting et des Services Packs du Framework .NET.

Comme vous le savez sûrement, Visual Studio 2008 vous permet de choisir une version cible du Framework .NET pour vos projets.
Ceci vous permet donc de développer des projets pour les Frameworks 2.0, 3.0 ou 3.5 à l'aide d'un même outil.

Cependant il pourrait être intéressant de savoir lors de vos développements si vous utilisez une classe, un type ou une méthode apporté(e) par un Service Pack du Framework .NET cible, et qui n'était donc pas présente dans la version RTM du Framework en question.

A première vue, on pourrait se demander pourquoi car il va de soi que tout bon développeur s'assure bien évidemment qu'il va déployer son application sur des machines ayant la même version du Framework .NET, avec le même Service Pack que la plateforme de développement.

Toutefois, cela se complique un peu avec le Framework .NET 3.5 Service Pack 1 qui installe le Service Pack 2 du Framework .NET 2.0.

En effet, ce Service Pack 2 n'est pas installable seul (pour le moment en tous cas, affaire à suivre...), il ne s'installe que par l'installation du SP1 du Framework .NET 3.5.

Voici au passage un rappel de là où nous en sommes des versions de Visual Studio et de CLR.

Imaginons alors une équipe de développement qui souhaite utiliser Visual Studio 2008 SP1 pour continuer à créer des applications .NET 2.0 SP1, car son parc de machines clientes n'est équipé que du Framework .NET 2.0 SP1, et que la migration vers le Framework .NET 3.5 SP1 n'est pas à l'ordre du jour.
Cette équipe risque alors de développer en utilisant des nouvelles fonctionnalités du Framework .NET SP2, alors que le parc ciblé n'en est qu'au SP1.
Si les développeurs utilisent une classe, un type ou une méthode apportée par le Service Pack 2, vous imaginez bien que des problèmes vont vite faire surface.

J'espère que vous m'avez suivi jusque là, sinon relisez le passage précédent au calme :o)

Afin d'éviter donc d'utiliser des fonctionnalités apportées par un Service Pack donné, vous pouvez utiliser l’outil d’analyse de code (Code Analysis).
Cet outil contient une règle afin de vous prévenir si vous utilisez une fonctionnalité qui ne sera pas présente sur les postes cibles car le niveau de service pack est différent. Plus précisément cette règle vous indiquera si vous utilisez une fonctionnalité apportée par un Service Pack du Framework .NET, par rapport au Framework .NET cible de votre projet.

Il faut pour cela activer une règle dans l’onglet Code Analysis des propriétés de votre projet, cette règle n’est disponible que pour les versions Visual Studio Team Development et Visual Studio Team Suite.

Si vous n'avez pas une de ces versions de Visual Studio, alors vous pouvez obtenir la même option avec l'outil FxCop.

L'analyse de votre application via Code Analysis ou FxCop lèvera alors un avertissement si vous utilisez une fonctionnalité apportée par un Service Pack des Framework 2.0, 3.0 ou 3.5.

L'article suivant de David Kean explique précisément comment utiliser ces outils, avec pleins de screenshots pour configurer tout ça : http://davesbox.com/archive/2008/08/25/new-for-visual-studio-2008-sp1-and-fxcop-1-36-multi-targeting-rule.aspx. Merci à lui pour cette synthèse.

A bientôt,
Aurélien

Supprimer la bordure 3D d'une fenêtre MDI parent

Bonjour,

Lorsque vous créez une application Windows Forms MDI, il se peut que vous ayez envie d'avoir la fenêtre parent qui n'ait pas de bordure du tout (on a le droit, hein...).

Pour cela, vous positionnez alors la propriété IsMdiContainer à True pour indiquer que la fenêtre est le conteneur des fenêtres MDI, mais aussi la propriété FormBorderStyle à None afin de supprimer toute bordure sur cette fenêtre.

Vous compilez et exécutez votre application, mais vous constatez qu'une bordure de type 3D persiste :

Cette bordure qui persiste représente en fait la zone conteneur de la fenêtre MDI.

But du jeu : la supprimer.

La bordure en question n’est pas sur la Form MDI Parent elle-même, mais sur un contrôle de type MDIClient de cette Form (ce contrôle est positionné automatiquement dès que vous spécifiez IsMdiContainer="True".

 Le code suivant montre comment retrouver ce contrôle MDIClient et supprimer sa bordure, à l'aide d'APIs Win32:

MdiClient mdiClient = null;
// Parcourt des contrôles de la Form
for (int i = 0; i < this.Controls.Count; i++)
{

// Si le Form est un MDI Container, il contient un client MDIClient
mdiClient = this.Controls[i] as MdiClient;
if (mdiClient != null)
{

break;

}

}

// Si le contrôle MDIClient est trouvé
if (mdiClient != null)
{

int iStyle = Win32.GetWindowLong(mdiClient.Handle, Win32.GWL_EXSTYLE);
//Suppression du style WS_EX_CLIENTEDGE des styles étendus du contrôle courant
iStyle &= ~Win32.WS_EX_CLIENTEDGE;
//Application du nouveau style
iStyle = Win32.SetWindowLong(mdiClient.Handle, Win32.GWL_EXSTYLE, iStyle);

}

Où Win32 est une classe statique reprenant certains appels aux APIs système et certaines constantes Win32.
Par exemple :

static public class Win32
{

[DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr window, int index);

[
DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr window, int index, int value);

public const int GWL_EXSTYLE = -20;
public const int WS_EX_CLIENTEDGE = 0x00000200;

}

Le résultat obtenu est le suivant :

La bordure a bien disparu !

A bientôt,
Aurélien

Lancement de mon Blog

Bonjour à tous,

Je m'appelle Aurélien Norie, je suis ADC (Application Development Consultant) chez Microsoft France.
Je suis en charge du suivi d'un portefeuille de clients afin de les conseiller proactivement ou réactivement sur tout type de demande sur la plateforme de développement Microsoft.

Avant cette expérience de conseil, j'ai passé quatre ans et demi en tant qu'ingénieur support pour les développeurs, puis un an et demi en tant que développeur d'applications internes, tout cela chez Microsoft France que j'ai rejoint en 2001.

L'objectif de ce blog est de partager des exemples de code, conseils techniques, astuces afin de faire profiter à un maximum de développeurs le fruit de mes recherches.

N'hésitez pas à laisser des commentaires que je lirai avec plaisir.

A très bientôt pour le premier post technique.
Aurélien Norie

Page view tracker