[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 :
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 :

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 !!
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :