【问题标题】:OnVisualChildrenChanged is called before dependency properties are set在设置依赖属性之前调用 OnVisualChildrenChanged
【发布时间】:2014-03-23 15:17:53
【问题描述】:

我创建了一个自定义控件 (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>

【问题讨论】:

    标签: wpf xaml custom-controls dependency-properties


    【解决方案1】:

    WPF 相当复杂,尤其是在编写自定义控件时,因此我的第一个建议是 - 离开它。将一个已经存在的控件或几个已经存在的控件组合到 UserControl 中,而不是从头开始编写所有内容。

    WPF 中的控件可以包含任何其他控件,并且仅在需要时才加载控件的子项。这就是你遇到问题的原因。

    解决方案是当OnVisualChildrenChanged 事件触发时,您应该遍历所有子节点并订阅它们的 Initialized 或 Loaded 事件。加载孩子后,事件将触发并调用处理程序。此外,在处理程序中,您不应该忘记取消订阅事件。

    【讨论】:

      猜你喜欢
      • 2010-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-04
      • 1970-01-01
      • 1970-01-01
      • 2011-02-02
      • 1970-01-01
      相关资源
      最近更新 更多