WPF VisualTreeHelper.GetParent возвращает неправильный класс?
У меня установлен следующий XAML.
<Popup x:Class="EMS.Controls.Dictionary.MapTip"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
PopupAnimation="Slide"
AllowsTransparency="True" Placement="Mouse"
x:Name="root"
>
<Popup.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources/Styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Popup.Resources>
<Viewbox x:Name="viewBox" IsHitTestVisible="True">
<Grid Background="Transparent" Name="mainGrid">
</Grid>
</Viewbox>
</Popup>
Если я подхожу к визуальному дереву с помощью VisualTreeHelper.GetParent из "mainGrid", я в конечном итоге получаю System.Windows.Controls.Primitives.PopupRoot, но никогда не получаю всплывающее окно. Кто-нибудь с теорией о том, почему это и что я могу с этим сделать? Я использую Popup, а не PopupRoot.
ТИА.
Ответы
Ответ 1
Содержимое всплывающего окна добавляется в другое визуальное дерево с родителем, который является PopupRoot, но вы можете использовать помощник логического дерева, чтобы получить всплывающее окно с этим фрагментом:
LogicalTreeHelper.GetParent()
От MSDN:
Когда вы добавляете контент в элемент управления Popup, элемент управления Popup становится логическим родителем для содержимого. Точно так же содержимое Popup считается логическим дочерним элементом Popup. Детский контент не добавляется в визуальное дерево, содержащее элемент управления Popup. Вместо этого дочерний контент отображается в отдельном окне, которое имеет собственное визуальное дерево, если для свойства IsOpen установлено значение true.
++
Ответ 2
Попробуйте пройти логическое дерево, а не дерево дерева
LogicalTreeHelper.GetParent()
Ответ 3
LogicalTreeHelper
не может достигнуть всплывающего окна, а лучшее, что можно сделать, это попытаться использовать имя "PopupRoot" для сравнения с GetType().Name
.
Ответ 4
Используйте это:
Popup oPopup = VisualHelper.GetLogicalParent<Popup>(oThumb);
...
public static T GetLogicalParent<T>(DependencyObject p_oElement)
where T : DependencyObject
{
DependencyObject oParent = p_oElement;
Type oTargetType = typeof(T);
do
{
oParent = LogicalTreeHelper.GetParent(oParent);
}
while (
!(
oParent == null
|| oParent.GetType() == oTargetType
|| oParent.GetType().IsSubclassOf(oTargetType)
)
);
return oParent as T;
}
Ответ 5
Основываясь на этом ответе и ответах, представленных здесь (и благодаря комментарию Wouter), я наконец-то придумал это:
using System.Windows.Media;
using System.Windows.Media.Media3D;
public static class FamilyHelper
{
public static T FindAncestor<T>(this DependencyObject dObj) where T : DependencyObject
{
var uiElement = dObj;
while (uiElement != null)
{
uiElement = VisualTreeHelper.GetParent(uiElement as Visual ?? new UIElement())
?? VisualTreeHelper.GetParent(uiElement as Visual3D ?? new UIElement())
?? LogicalTreeHelper.GetParent(uiElement);
if (uiElement is T) return (T) uiElement;
}
return null;
}
}
который никогда не ошибается и работает для всех типов контроля, например
var element = sender as UIElement;
var parentWindow = element.FindAncestor<Window>();
Ответ 6
private void btnRemove_Click(object sender, RoutedEventArgs e)
{
CloseScatterViewItem((SurfaceButton)sender);
}
private void CloseScatterViewItem(SurfaceButton button)
{
DependencyObject parent = button;
while ((parent as ScatterViewItem) == null)
{
// Get the next parent.
parent = LogicalTreeHelper.GetParent(parent) != null ? LogicalTreeHelper.GetParent(parent) : VisualTreeHelper.GetParent(parent);
ScatterViewItem item = parent as ScatterViewItem;
if (item != null)
{
DependencyObject scatterView = item;
while ((scatterView as ScatterView) == null)
{
scatterView = LogicalTreeHelper.GetParent(scatterView) != null ? LogicalTreeHelper.GetParent(scatterView) : VisualTreeHelper.GetParent(scatterView);
ScatterView FoundSV = scatterView as ScatterView;
if (FoundSV != null)
{
//FoundSV.Items.Remove(item);
FadeOutAndRemove(FoundSV, item);
return;
}
}
}
}
}
public static void FadeOutAndRemove(ScatterView sv, ScatterViewItem svi)
{
try
{
svi.Opacity = 1.0;
var a = new DoubleAnimation
{
From = 1.0,
To = 0.0,
FillBehavior = FillBehavior.Stop,
BeginTime = TimeSpan.FromSeconds(0),
Duration = new Duration(TimeSpan.FromSeconds(0.5))
};
var storyboard = new Storyboard();
storyboard.Children.Add(a);
Storyboard.SetTarget(a, svi);
Storyboard.SetTargetProperty(a, new PropertyPath(UIElement.OpacityProperty));
storyboard.Completed += delegate
{
svi.Visibility = Visibility.Hidden;
sv.Items.Remove(svi);
svi.Content = null;
svi = null;
};
storyboard.Begin();
}
catch (Exception ex)
{
//Handle error
}
}