2009-03-13 4 views
0

J'essaie de créer un panneau personnalisé qui utilise une positionion absolue, mais qui réorganise les éléments de façon à ce qu'aucun des enfants ne se chevauche. Ce panneau sera utilisé pour le ItemsPanel d'un ItemsControl. Le ItemsControl est lié à des données qui sont affichées comme un encart sur une carte pour différentes villes afin que le but est de garder les encarts au plus près de leurs villes sans chevauchement d'autres encarts. J'ai un algorithme pour réorganiser les éléments (bien que ce soit lent et je suis intéressé à en trouver un meilleur, donc si quelqu'un a des suggestions, s'il vous plaît faites le moi savoir), mais j'ai vraiment lutté avec le panneau personnalisé.Comment créer un panneau Silverlight qui organise les éléments enfants pour éviter les chevauchements?

Le dernier code peut être trouvé ci-dessous moins l'algorithme pour le garder plus court. J'ai également joint une image de ce à quoi ressemble l'arbre visuel sous overlappanel.

Problèmes:

1.) La première question que je suis tombé sur est que, malgré MSDN disant que MeasureOverride doit retourner une hauteur et la largeur de l'infini positif si elle veut prendre tout l'espace disponible, je reçois une erreur quand j'essaye de le faire. En raison de cela, j'ai un problème où certains de mes éléments enfants sont tronqués car le ItemsPresenter qui contient le OverlapPanel est uniquement dimensionner à la taille MeasureOverride retournée et écrêter certains de mes insets car après ArrangeOverride, ils sont déplacés et la taille finale est plus grande.

2.) J'essayé d'utiliser VisualTreeHelper.FindElementInHostCoordinates en utilisant les propriétés Canvas.Left et Canvas.Top de chaque « ItemsControl » quelques niveaux sous le « ContentPresenter » de chaque encart pour trouver d'autres éléments qui se chevauchent dans la sous-arborescence OverlapPanel. La raison pour laquelle j'ai dû explorer le ItemsControl est parce que c'est le premier élément avec les propriétés canvas.top et left valides ainsi que DesiredSize.Width et DesiredSize.Height. Cependant, FindElementInHostCoordinates renvoyait 0 éléments peu importe ce que je semblais essayer. J'ai même essayé d'utiliser TransformToVisual pour traduire mes coordonnées à différents niveaux avant de l'utiliser et je n'ai toujours pas obtenu les résultats attendus. 3) Puisque j'utilise le OverlapPanel en tant que ItemsPanel pour un ItemsControl, je dois descendre dans l'arbre visuel de deux niveaux pour obtenir une valeur réelle gauche/haut et largeur/hauteur pour calculer le positionnement mais ceci ne permettrait pas que le panneau soit utilisé comme un panneau générique. Comment pourrais-je rendre cela plus utilisable dans son ensemble?

Voici le code avec lequel je travaille actuellement. Notez que "PreArrange" est ce qui finit par appeler "Arrange" sur chaque élément enfant, et définit ses propriétés left/top. Je suis parti le code correspondant pour la brièveté .:

Protected Overrides Function MeasureOverride(ByVal availableSize As System.Windows.Size) As System.Windows.Size 
     'Return MyBase.MeasureOverride(availableSize) 
     Dim infinite As New Size(Double.PositiveInfinity, Double.PositiveInfinity) 

     Dim maxX, maxY As Double 
     maxX = 0 
     maxY = 0 

     For Each elem As FrameworkElement In Children 
      elem.Measure(infinite) 
      Dim ic As ItemsControl = CType(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(elem, 0), 0), ItemsControl) 
      If (elem.GetValue(Canvas.LeftProperty) + ic.DesiredSize.Width) > maxX Then 
       maxX = elem.GetValue(Canvas.LeftProperty) + ic.DesiredSize.Width 
      End If 
      If (elem.GetValue(Canvas.TopProperty) + ic.DesiredSize.Height) > maxY Then 
       maxY = elem.GetValue(Canvas.TopProperty) + ic.DesiredSize.Height 
      End If 
     Next 

     Return New Size(maxX, maxY) 
    End Function 

    Protected Overrides Function ArrangeOverride(ByVal finalSize As System.Windows.Size) As System.Windows.Size 
     If Children.Count = 0 Then 
      Return MyBase.ArrangeOverride(finalSize) 'New Size(Width, Height) 
     End If 

     Dim maxX As Double = 0 
     Dim minX As Double = 0 
     Dim maxY As Double = 0 
     Dim minY As Double = 0 

     For i As Integer = 0 To Children.Count - 1 
      PreArrange(Children(i), 5, 1, 10) 
      Dim ic As ItemsControl = CType(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(Children(i), 0), 0), ItemsControl) 
      Dim x1 As Double = Children(i).GetValue(Canvas.LeftProperty) 
      Dim x2 As Double = ic.DesiredSize.Width + x1 
      Dim y1 As Double = Children(i).GetValue(Canvas.TopProperty) 
      Dim y2 As Double = ic.DesiredSize.Height + y1 

      If x1 < minX Then minX = x1 
      If x2 > maxX Then maxX = x2 
      If y1 < minY Then minY = y1 
      If y2 > maxY Then maxY = y2 
     Next 


     Return New Size(Math.Abs(minX) + maxX, Math.Abs(minY) + maxY) 
     'Return MyBase.ArrangeOverride(finalSize) 
    End Function 

alt text http://www.mistertnt.com/images/OverlapPanelVisualTree.jpg

Répondre

Questions connexes