我正在尝试创建一个使用绝对定位的自定义面板,但会重新排列项目,以便所有子项都不会重叠。此面板将用于ItemsControl的ItemsPanel。 ItemsControl绑定到在各个城市的地图上显示为插入的数据,因此目标是使插图保持接近其城市而不重叠任何其他插入。我有一个重新排列项目的算法(虽然它很慢,我有兴趣找到一个更好的,所以如果有人有建议,请告诉我),但我一直在努力与自定义面板。
最新的代码可以在下面找到减去算法以缩短它。我还附上了一个图像,显示了视觉树在重叠区域下的样子。
问题:
1。)我遇到的第一个问题是,尽管MSDN说如果想要占用可用的全部空间,MeasureOverride应该返回正无穷大的高度和宽度,当我尝试这样做时会出现错误。因此,我遇到了一些问题,其中我的一些子项被剪切,因为包含OverlapPanel的ItemsPresenter仅调整返回的MeasureOverride大小并剪切我的一些插图,因为在ArrangeOverride之后,它们被移动并且最终尺寸更大。
2.。)我尝试使用VisualTreeHelper.FindElementInHostCoordinates,使用每个“ItemsControl”的Canvas.Left和Canvas.Top属性,在每个插图的“ContentPresenter”下面的几个级别找到OverlapPanel子树中的其他重叠项。我必须深入到ItemsControl的原因是因为它是第一个具有有效canvas.top和left属性以及DesiredSize.Width和DesiredSize.Height的项目。但是,无论我试图尝试什么,FindElementInHostCoordinates都会返回0项。我甚至尝试使用TransformToVisual将我的坐标转换为各种级别,然后再使用它,我仍然无法得到任何预期的结果。
3。)由于我使用OverlapPanel作为ItemsControl的ItemsPanel,我必须向下钻取几个级别的可视树以获得实际的左/顶值和宽度/高度来计算定位但这不会不允许面板用作通用面板。我怎么能让它在整体上变得更有用呢?
这是我目前正在使用的代码。请注意,“PreArrange”最终会在每个子元素上调用“Arrange”,并设置其左/顶属性。为了简洁,我把代码留给了它。:
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
答案 0 :(得分:0)
查看DragDockPanel here:
http://mightymeaty.members.winisp.net/blacklight.silverlight/