I have the following code
public partial class MyControl : UserControl
{
...
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
if (DataContext is MyViewModel)
{
var vm = DataContext as CameraViewModel;
var p = Parent as FrameworkElement;
while (!(p is Window))
p = p.Parent as FrameworkElement;
vm.GetTransform = () => TransformToAncestor(p);
}
}
}
And in my viewmodel I have a command handler code, executes when a button in my user control being clicked.
public Func<GeneralTransform> GetTransform { private get; set; }
private void OnMyCommand(object parameter){
var p = GetTransform().Transform(new Point(0,0));
}
But the above code does not work, as the GetTransform()
call says
The specified Visual is not an ancestor of this Visual.
I think my code above is already ensured that p
is the window ancestor of the control, but why I still get this error?
Thanks to @Brian Reichle's comment, I figured out the reason and resolved it.
It turn out to be the case that I have the same control in different tabs of a tab control.
As you should know, there is only one tab can be active at all times. Those controls belong to tabs that currently inactive are belong to different visual trees that don't have a window ancestor.
In my case, this is what happened: I track back the logical tree to figure out the Window
object, but the this
object is belong to some invisible tabs and don't have that Window
as its visual ancestor.
Once realized this, the solution is then not to attach Loaded
event, but attach IsVisibleChanged
event.
private void UserControl_IsVisibleChanged(object sender,
DependencyPropertyChangedEventArgs e)
{
if (!(bool)e.NewValue)
return;
if (DataContext is CameraViewModel)
{
SaveTransform();
}
else Dispatcher.InvokeAsync(SaveTransform);
}
private void SaveTransform()
{
var vm = DataContext as CameraViewModel;
var w = VisualTreeHelper.GetParent(this) as FrameworkElement;
while (w != null && !(w is Window))
w = VisualTreeHelper.GetParent(w) as FrameworkElement;
if (w != null)
{
vm.GetTransform = () => TransformToAncestor(w);
}
}
Note: in the first fire of IsVisibleChanged
event the data context might not being set yet. So the above code have to postpond the SaveTransform
code later.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.