我创建了一个自定义控件(CartesianCanvas),它可以在添加任何子元素时存储其中的一些属性。为此,我创建了一个新的集合属性(ItemsInfo)并覆盖了OnVisualChildrenChanged,以便在添加或删除子项时,从集合属性中添加或删除相应的属性。
但是,当我通过XAML向控件添加子项时,OnVisualChildrenChanged将在设置属性之前调用它们,因为所有属性都具有其默认值。在窗口加载后添加子项时不是这种情况。如何在调用OnVisualChildrenChanged时确保已设置子属性?
这是我的代码:
Public ReadOnly Property ItemsInfo As Collection(Of CartesianInfo)
Get
Return DirectCast(GetValue(ItemsInfoProperty), Collection(Of CartesianInfo))
End Get
End Property
Friend Shared ReadOnly ItemsInfoKey As System.Windows.DependencyPropertyKey = System.Windows.DependencyProperty.RegisterReadOnly("ItemsInfo", GetType(Collection(Of CartesianInfo)), GetType(CartesianCanvas), New System.Windows.PropertyMetadata(New Collection(Of CartesianInfo)))
Public Shared ReadOnly ItemsInfoProperty As DependencyProperty = ItemsInfoKey.DependencyProperty
Protected Overrides Sub OnVisualChildrenChanged(visualAdded As DependencyObject, visualRemoved As DependencyObject)
Try
If Not visualAdded Is Nothing Then
If Not GetType(FrameworkElement).IsAssignableFrom(visualAdded.GetType) Then
Me.Children.Remove(visualAdded)
Throw New Exception("The object added:" & visualAdded.ToString & " was not of type or decended from: FrameworkElement and so was removed from CartesianCanvas")
Else
AddItemInfo(visualAdded)
End If
End If
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
If Not visualRemoved Is Nothing Then
RemoveItemInfo(visualRemoved)
End If
MyBase.OnVisualChildrenChanged(visualAdded, visualRemoved)
End Sub
Private Sub AddItemInfo(ByRef item As FrameworkElement)
Dim itemsInfoCollection As New Collection(Of CartesianInfo)
itemsInfoCollection = ItemsInfo
Dim ItemXCoordinate As Double
Dim ItemYCoordinate As Double
Dim ItemCalculateFromVerticalCenter As Boolean
Dim ItemCalculateFromHorizontalCenter As Boolean
If Double.IsNaN(Canvas.GetLeft(item)) Then
Canvas.SetLeft(item, 0)
End If
If Double.IsNaN(Canvas.GetTop(item)) Then
Canvas.SetTop(item, 0)
End If
ItemXCoordinate = Canvas.GetLeft(item)
ItemYCoordinate = Canvas.GetTop(item)
If item.VerticalAlignment = Windows.VerticalAlignment.Center Then
ItemCalculateFromVerticalCenter = True
End If
If item.HorizontalAlignment = Windows.HorizontalAlignment.Center Then
ItemCalculateFromHorizontalCenter = True
End If
ItemsInfo.Add(New CartesianInfo(item, ItemXCoordinate, ItemYCoordinate, ItemCalculateFromVerticalCenter, ItemCalculateFromHorizontalCenter))
SetValue(ItemsInfoKey, ItemsInfo)
PositionChild(item)
End Sub
这是我的XAML
<local:CartesianCanvas x:Name="MainCanvas">
<Button Width="50" Height="100" Canvas.Top="100" Canvas.Left="20"
Content="test" Click="Button_Click"/>
</local:CartesianCanvas>
答案 0 :(得分:1)
WPF非常复杂,特别是在编写自定义控件时,因此我的第一个建议是 - 保留它。将现有的控件或几个已存在的控件复合到UserControl
中,而不是从头开始编写所有内容。
WPF中的控件可能包含任何其他控件,并且仅在需要时才加载控件的子控件。这就是你遇到问题的原因。
解决方案是当OnVisualChildrenChanged
事件触发时,您应该遍历所有子节点并订阅其Initialized或Loaded事件。加载子项后,将触发事件并调用处理程序。此外,在处理程序中,您不应该忘记取消订阅活动。