wPF VisualTreeHelper.GetParent返回错误的类?

时间:2010-09-25 14:14:47

标签: wpf

我定义了以下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>

如果我使用来自“mainGrid”的VisualTreeHelper.GetParent走向可视树,我最终得到System.Windows.Controls.Primitives.PopupRoot,但永远不会获得Popup本身。任何人都有关于为什么会这样做以及我能做些什么的理论?我需要Popup而不是PopupRoot。

TIA。

6 个答案:

答案 0 :(得分:16)

弹出窗口中的内容会添加到不同的可视树中,其父级是PopupRoot,但您可以使用逻辑树助手来获取此代码段的弹出窗口:

LogicalTreeHelper.GetParent()

来自MSDN:

  

向Popup控件添加内容时,Popup控件将成为内容的逻辑父级。同样,Popup内容被认为是Popup的逻辑子代。子内容未添加到包含Popup控件的可视树中。相反,当IsOpen属性设置为true时,子内容将在单独的窗口中呈现,该窗口具有自己的可视树。

++

答案 1 :(得分:4)

尝试遍历逻辑树而不是Visual树

LogicalTreeHelper.GetParent()

答案 2 :(得分:4)

LogicalTreeHelper无法访问Popup,最好的方法是尝试使用“PopupRoot”命名与GetType().Name进行比较。

答案 3 :(得分:3)

使用此:

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;
}

答案 4 :(得分:2)

基于this answer以及此处提供的答案(感谢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
    {
        while (true)
        {
            if (dObj == null) return null;

            var parent = VisualTreeHelper.GetParent(dObj as Visual ?? new UIElement())
                         ?? VisualTreeHelper.GetParent(dObj as Visual3D ?? new UIElement())
                         ?? LogicalTreeHelper.GetParent(dObj);

            if (parent is T) return (T) parentT;
            dObj = parent;
        }
    }
}

永远不会出错,适用于所有类型的控件,例如

var element = sender as UIElement;
var parentWindow = element.FindAncestor<Window>();

答案 5 :(得分:1)

    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

        }
    }