Dans WPF, il existe de nombreuses solutions à la plupart des problèmes. Je vais discuter de trois solutions possibles à votre problème - celui que vous décrivez et deux autres. Vous pouvez décider lequel fonctionnera le mieux pour vous.
Solution 1: Utilisation d'objets TextBlock disply les étiquettes
Il semble que vous avez un Canvas
et vous ajoutez un TextBlock
à elle pour chaque coche. C'est une solution viable si les performances ne sont pas trop critiques et que vous ne pouvez pas utiliser la liaison de données.
Il y a deux façons d'éliminer les TextBlocks dans ce cas:
Vous pouvez garder un List<TextBlock>
contenant toute la liste des TextBlocks Zones de texte que vous avez créé la dernière fois que vous avez créé les étiquettes. Chaque fois que vous recréez les étiquettes, parcourez cette liste et supprimez chaque TextBlock de la liste à partir du panneau contenant (le Canevas)
Vous pouvez créer un nouveau Canevas et y placer les TextBlocks, puis supprimer le Canvas entier quand vous le souhaitez. relabel.
Voici un exemple de la seconde technique, car il est un peu plus efficace:
class MyGraphBuilder
{
Canvas _labelCanvas;
...
void AddLabels()
{
// Remove old label canvas, if any
if(_labelCanvas!=null)
_graphCanvas.Children.Remove(_labelCanvas);
// Add new label canvas
_labelCanvas = new Canvas();
_graphCanvas.Children.Add(_labelCanvas);
// Create labels
foreach(...)
{
...
_labelCanvas.Add(new TextBlock ...
}
...
}
}
Solution 2: données à l'aide de liaison
Dans WPF, vous pouvez créer de nombreux graphiques sans écrire une seule ligne de code! WPF construit dans la liaison de données est suffisante pour créer des diagrammes à barres relativement complexes, etc.
Voici un exemple d'utilisation de liaison de données pour créer un graphique simple barre:
<ItemsControl ItemsSource="{Binding myData}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DockPanel>
<TextBlock Width="50" Text="{Binding Label}"/>
<Rectangle VerticalAlignment="{Stretch}" Width="{Binding Value}">
<Rectangle.LayoutTransform>
<ScaleTransform ScaleX="10" /> <!-- Scale factor here, can be binding too -->
</Rectangle.LayoutTransform>
</Rectangle>
<TextBlock Text="{Binding Value}" FontSize="8"/>
</DockPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
étiquettes numériques peuvent être ajoutés à l'horizontale axe en utilisant un second ItemsControl disposé horizontalement, et avec son modèle de données une largeur fixe et en montrant les numéros et les graduations.
Solution 3: Utilisation des classes à faible niveau de dessin
construire votre graphique en construisant un objet DrawingGroup
et en ajoutant GeometryDrawing
et GlyphRunDrawing
objets, mettant alors le DrawingGroup
intérieur DrawingVisual
et ajouter à votre principale Panel
.
Vous devez utiliser un GeometryDrawing
ou un GlyphRunDrawing
pour chaque ensemble d'éléments partageant une brosse et un stylo donnés. Par exemple, si vos axes et graduations sont tous de la même couleur et de la même largeur, créez un seul GeometryDrawing
pour chacun d'eux, mais si chaque marque est une couleur différente, créez plusieurs objets GeometryDrawing
.
Vous allez créer un objet Geometry
pour chaque GeometryDrawing
. Pour une meilleure efficacité, il doit s'agir d'un StreamGeometry
, mais les autres classes de géométrie fonctionnent également bien, peuvent être plus faciles à utiliser et peuvent être initialisées en XAML. Créer un PathGeometry
ou EllipseGeometry
est probablement déjà familier à vous donc je vais me concentrer sur la création d'un StreamGeometry
. Pour ce faire, appelez la méthode Open
dans une instruction using()
, puis écrivez dans le contexte renvoyé. Voici un exemple:
Geometry BuildAxesAndTicksGeometry()
{
// First create geometry
var geometry = new StreamGeometry();
using(var context = geometry.Open())
{
// Horizontal axis
context.BeginFigure(new Point(0,0), false, false);
context.LineTo(new Point(_width, 0), true, false);
// Vertical axis
context.BeginFigure(new Point(0,0), false, false);
context.LineTo(new Point(0, _height), true, false);
// Horizontal ticks
for(int i=0; i<_nTicksHorizontal; i++)
{
context.BeginFiture(new Point(i * _tickSpacing, -10), false, false);
context.LineTo(new Point(i * _tickSpacing, 10), true, false);
}
// Do same for vertical ticks
}
// Now add it to a drawing
return new GeometryDrawing { Geometry = geometry, Stroke = _axisPen };
}
Drawing BuildDrawing()
{
var mainDrawing = new DrawingGroup();
mainDrawing.Add(BuildAxesAndTicksGeometry());
... // Add other drawings, including one or more for the data
return mainDrawing;
}
void UpdateDrawing()
{
myDrawingVisual.Drawing = BuildDrawing(); // where myDrawingVisual is defined in the XAML
}
Comparaison des solutions
Pour la plupart des cas, je recommande la solution 2 ou 3, pour ces raisons:
- Si le graphique est assez simple à utiliser la liaison de données vous permettra d'économiser beaucoup de temps. Aller avec la solution 2.
- Si le graphe ne peut pas être fait avec la liaison de données, l'utilisation d'objets de dessin est à peu près aussi simple que n'importe quelle autre technique, et peut mieux fonctionner. Optez pour la solution 3.
Dans votre cas, si vous avez déjà investi beaucoup de temps dans votre solution 1, vous pouvez conserver cette solution même si elle n'est probablement pas la meilleure.