Подтвердить что ты не робот

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.

ТИА.

4b9b3361

Ответ 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

        }
    }