絶対位置指定を使用するカスタムパネルを作成しようとしていますが、子が重ならないようにアイテムを並べ替えます。このパネルは、ItemsControlのItemsPanelに使用されます。 ItemsControlは、さまざまな都市のマップにインセットとして表示されるデータにバインドされているため、他のインセットと重複することなくインセットを都市の近くに保つことが目標です。私はアイテムを並べ替えるアルゴリズムを持っています(それは遅いですが、誰かが提案をしてくれればより良いものを探したいと思っています。私に教えてください)。しかし、私はカスタムパネルで本当に苦労しています。重複を避けるために子アイテムを配置するSilverlightパネルを作成するにはどうすればよいですか?
最新のコードは、アルゴリズムを削除して、それを短くすることができます。また、オーバーラッパーの下でビジュアルツリーがどのように見えるかのイメージを添付しました。
問題:
1)私はに走った最初の問題MSDNはそれが可能な、完全なスペースを取るしたい場合はMeasureOverrideが正の無限大の高さと幅を返すべきであると言ってもかかわらず、私はエラーを取得するということです私がそうしようとするとき。この結果、OverlapPanelを含むItemsPresenterは、返されたMeasureOverrideサイズにサイジングするだけで、いくつかの私のインセットがクリップされてしまう問題があります。なぜなら、ArrangeOverrideの後で、最終的なサイズが大きくなります。
2)OverlapPanelサブツリー内の他のオーバーラップアイテムを見つけるために、各インセットの "ContentPresenter"の下にある各ItemsControlのCanvas.LeftおよびCanvas.Topプロパティを使用してVisualTreeHelper.FindElementInHostCoordinatesを使用してみました。 ItemsControlをドリルダウンしなければならないのは、有効なcanvas.topとleftプロパティ、DesiredSize.WidthとDesiredSize.Heightを持つ最初のアイテムだからです。しかし、FindElementInHostCoordinatesは何を試してみても0のアイテムを返していました。私はTransformToVisualを使って座標をさまざまなレベルに翻訳してみましたが、それを使用する前に私はまだ予想どおりの結果を得ることができませんでした。
3)私はItemsControlのItemsPanelとしてOverlapPanelを使用しているので、実際の左/上の値と幅/高さを計算するためにビジュアルツリーにドリルダウンする必要がありますが、これはパネルを汎用パネルとして使用することはできません。どのようにすれば、これを全体としてより使いやすくすることができますか?
私は現在作業しているコードです。 「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