2016-09-07 1 views
2

J'ai construit un contrôle personnalisé qui hérite de la toile. Il utilise la méthode ArrangeOverride pour ajouter une fonctionnalité de glisser-déposer à tous les éléments enfants, et cela inclut l'alignement de la grille sur 50 pixels et d'autres comportements personnalisés tels que la persistance des positions des éléments. Ce que je voudrais vraiment faire est de prolonger cela de sorte que tout en faisant glisser, il montre une grille de points ou de croix en arrière-plan afin que vous puissiez voir où sont les points d'accrochage.Puis-je dessiner une grille de points dans un contrôle de canevas WPF personnalisé?

Cependant, je ne peux pas modifier le modèle du contrôle parce que c'est un panneau. J'ai essayé d'en faire un contrôle personnalisé qui contient un canevas, et en passant la source d'éléments IEnumerable, mais il est devenu très difficile de comprendre le changement de collection, et la collection contenait alors des modèles et non des éléments de charpente. Donc, je ne suis pas sûr du chemin que je devrais suivre. J'ai l'impression qu'il y a peut-être une solution très simple que j'ai oubliée, alors je suis ouvert aux suggestions!

Merci d'avance.

Répondre

2

J'ai fait quelque chose de similaire une fois: dessiner les lignes de la grille sur UserControl, puis ajouter des contrôles dessus. C'était pour une simple application de planification utilisée pour assigner qui travaillera quel quart dans le mois courant. Je devais avoir des en-têtes de colonne (jours) et des en-têtes de rangée (personnes) et une grille défilante à l'intérieur, à laquelle je pourrais ajouter/enlever des contrôles. Je ne sais pas dans quelle mesure ma solution vous aidera, mais c'est ici. J'ai utilisé HeaderedScrollViewer de here. UCHeader est un UserControl avec des zones de texte avec des dates. La magie se produit dans le UC_GridLines.

<Grid> 
    <lib:HeaderedScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Background="AliceBlue"> 
    <lib:HeaderedScrollViewer.TopHeader> 
     <lib:UCHeader Name="ucHeader"/> 
    </lib:HeaderedScrollViewer.TopHeader> 
    <lib:HeaderedScrollViewer.LeftHeader> 
     <Border BorderBrush="Black" BorderThickness="1,2,1,1"> 
      <StackPanel Orientation="Vertical" Name="spRows" /> 
     </Border> 
    </lib:HeaderedScrollViewer.LeftHeader> 
    <Grid Name="gridContentAll"> 
     <Border Canvas.ZIndex="1" Background="Transparent" 
      BorderThickness="1,1,1,2" BorderBrush="Transparent"> 
       <Grid ClipToBounds="True" Name="gridContent" Background="Transparent" /> 
     </Border> 
     <Border Canvas.ZIndex="0" BorderThickness="1,1,1,2" BorderBrush="Black" Background="White"> 
      <lib:UC_GridLines Name="ucGridLines" BorderThickness="0"/> 
     </Border> 
    </Grid> 
</lib:HeaderedScrollViewer> 
</Grid> 

importants sont:

  • Réglage Background="Transparent" pour le contrôle qui commande l'enfant
  • contenant
  • Réglage ZIndex correctement, de sorte que les contrôles sont présentés sur la grille.
  • Réglage SnapsToDevicePixels="True" et UseLayoutRounding="True" sur l'élément racine (par exemple la fenêtre)

UC_GridLines dans son fichier XAML n'a rien (seulement <Grid></Grid>). Dessiner les lignes de la grille se passe dans le codebehind:

protected override void OnRender(DrawingContext drawingContext) 
    { 
     // VM contains data of the grid, used to draw gridlines 
     // such as number of days etc. 
     if (this.VM == null) 
     { 
      base.OnRender(drawingContext); 
      return; 
     } 
     double dpiFactor = 1; 
     try 
     { 
      Matrix m = PresentationSource.FromVisual(this) 
        .CompositionTarget.TransformToDevice; 
      dpiFactor = 1/m.M11; 
     } 
     catch { } 

     Pen pen = new Pen(Brushes.Black, 1 * dpiFactor); 
     double halfPenWidth = pen.Thickness/2; 

     GuidelineSet guidelines = new GuidelineSet(); 

     double width = this.VM.Days.Count * this.VM.DayWidth - 16 * (this.VM.DayWidth/24); 
     double height = this.VM.RowHeight * rowCount; 

     for (int i = 1; i < this.VM.Days.Count; i++) 
     { 
      guidelines.GuidelinesX.Add(i * this.VM.DayWidth + halfDashPenWidth); 
     } 

     for (int i = 1; i < rowCount; i++) 
     { 
      guidelines.GuidelinesY.Add(i * this.VM.RowHeight + halfPenWidth); 
     } 

     drawingContext.PushGuidelineSet(guidelines); 

     for (int i = 1; i < this.VM.Days.Count; i++) 
     { 
      drawingContext.DrawLine(dashpen, new Point(i * this.VM.DayWidth, 0), new Point(i * this.VM.DayWidth, height)); 
     } 

     for (int i = 1; i < rowCount; i++) 
     { 
      drawingContext.DrawLine(pen, new Point(0, i * this.VM.RowHeight), new Point(width, i * this.VM.RowHeight)); 
     } 

     drawingContext.Pop(); 
    } 
+0

Merci Arie - c'est vraiment utile. Je viens de remplacer la méthode OnRender pour le contrôle personnalisé et ajouté une grille. Une idée de comment je pourrais seulement montrer la grille pendant que l'utilisateur traîne activement pourtant? Cette méthode de rendu est uniquement appelée initialement, puis lorsque je redimensionne le contrôle. Idéalement, ce serait génial de pouvoir le montrer et le cacher. –

+0

Peu importe - c'est en fait juste juste rester là. Je l'ai fait assez subtile. J'ai également dû ajouter base.OnRender (drawingContext) à la fin, sinon la performance de l'accrochage glisser/grille était vraiment mauvaise pour une raison quelconque. Merci encore pour l'exemple de code. –