有没有一种方法,在不重写OnVisualParentChanged方法的情况下,仅通过使用事件来通知FrameworkElement的可视父级发生更改?与此处提供的“Loaded”事件相比,这种方法似乎并不安全。是否有一种事件可以确切地在可视父级发生更改/已更改时触发?
void _Loaded(object sender, RoutedEventArgs e)
{
DoSmthng();
}
void _Unloaded(object sender, RoutedEventArgs e)
{
DoSmthngElse();
}
protected override void OnVisualParentChanged(DependencyObject oldParent)
{
DoSmthngOther();
// Call base class to perform standard event handling.
base.OnVisualParentChanged(oldParent);
}
OnVisualParentChanged
有些关联。在FrameworkElement.cs实现中,它会执行private void TryFireInitialized()
,进而调用protected virtual void OnInitialized(EventArgs e)
,因此您可以在那里挂钩。TryFireInitialized()
只会触发一次 OnInitialized
。 - HerpDerpington我最近遇到了一个情况,我真的需要知道任意元素何时获取其父级(一个我没有创建过的元素,所以我无法访问覆盖方法)。我编写了一个肮脏的hack,虽然它可能不是“安全”的,但确实可以工作。
令人烦恼的是,Visual
实际上有一个VisualAncestorChanged
事件!它正是我们想要的:在父项更改时立即触发。...唯一的问题是它是internal
的,所以你必须进入WPF源代码才能看到它。幸运的是,通过反射,像访问修饰符这样的东西变得更像建议。
这是我构建的类来钩住那个内部事件。该类公开了一个公共事件,您可以正常处理,它会由内部事件触发。
''' <summary>
''' Raises an event when the visual parent of a <see cref="Visual"/> changes.
''' </summary>
Public Class VisualAncestorWatcher
Implements IDisposable
Public Sub New(Visual As Visual)
Me.Visual = Visual
Dim HandlerType = InternalVisualAncestorChangedEvent.EventHandlerType
Dim Ctor = HandlerType.GetConstructor({GetType(Object), GetType(IntPtr)})
Dim HandlerMethod = [GetType].GetMethod("InternalVisualAncestorChangedHandler", BindingFlags.NonPublic Or BindingFlags.Instance)
CreatedDelegate = Ctor.Invoke({Me, HandlerMethod.MethodHandle.GetFunctionPointer})
InternalVisualAncestorChangedEvent.GetAddMethod(True).Invoke(Visual, {CreatedDelegate})
End Sub
Public ReadOnly Property Visual As Visual
Private CreatedDelegate As [Delegate]
Private Sub InternalVisualAncestorChangedHandler(sender As Object, e As Object)
RaiseEvent VisualAncestorChanged(sender, New AncestorChangedEventArgs(e))
End Sub
Public Event VisualAncestorChanged As EventHandler(Of AncestorChangedEventArgs)
Private Shared _InternalVisualAncestorChangedEvent As Reflection.EventInfo
Public Shared ReadOnly Property InternalVisualAncestorChangedEvent As Reflection.EventInfo
Get
If _InternalVisualAncestorChangedEvent Is Nothing Then _InternalVisualAncestorChangedEvent = GetType(Visual).GetEvent("VisualAncestorChanged", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)
Return _InternalVisualAncestorChangedEvent
End Get
End Property
#Region "IDisposable"
Private disposedValue As Boolean
Protected Overridable Sub Dispose(disposing As Boolean)
If Not disposedValue Then
If disposing Then
InternalVisualAncestorChangedEvent.RemoveMethod.Invoke(Visual, {CreatedDelegate})
End If
disposedValue = True
End If
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in 'Dispose(disposing As Boolean)' method
Dispose(disposing:=True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
Public Class AncestorChangedEventArgs
Public Sub New(internalArgs As Object)
Ancestor = internalArgs.Ancestor
OldParent = internalArgs.OldParent
End Sub
Public ReadOnly Property Ancestor As DependencyObject
Public ReadOnly Property OldParent As DependencyObject
End Class