WinRT/Metro:解析元素在Visual Tree和Logical Tree中的位置

严格上讲,Visual Tree和Logical Tree是WPF的概念,不过既然都有XAML,那么它们在WinRT中也是存在的。

首先WinRT中没有WPF中的Visual,UIElement是直接继承自DependencyObject的,然后下面是FrameworkElement。

image

接下来就是使用Windows.Ui.Xaml命名空间下的VisualTreeHelper类型,使用起来和WPF类似,比如根据当前元素查找上面的Visual Tree,代码:

IEnumerable<DependencyObject> GetVisualTree(DependencyObject obj)

{

var list = new List<DependencyObject>() { obj };

var res = obj;

while ((res = VisualTreeHelper.GetParent(res)) != null)

list.Add(res);

return list.AsEnumerable().Reverse();

}

比如我们在界面上放置一个ListBox(名称是lbx),使用上述自己输出自己的Visual Tree:

lbx.ItemsSource = GetVisualTree(lbx).Select(d => d.GetType().Name);

结果:

image

好了,接着看Logical Tree,不过WinRT目前还没有LogicalTreeHelper类型,不过我们可以通过FrameworkElement.Parent属性来获取对象的Logical Parent。

事实上WPF中的LogicalTreeHelper就是这样工作的,只不过同时支持FrameworkElement和FrameworkContentElement,如下WPF中LogicalTreeHelper.GetParent方法源码:

//WPF LogicalTreeHelper.GetParent

public static DependencyObject GetParent(DependencyObject current)

{

if (current == null)

{

throw new ArgumentNullException("current");

}

FrameworkElement element = current as FrameworkElement;

if (element != null)

{

return element.Parent;

}

FrameworkContentElement element2 = current as FrameworkContentElement;

if (element2 != null)

{

return element2.Parent;

}

return null;

}

因此获得Logical Tree,可以写如下方法:

IEnumerable<DependencyObject> GetLogicalTree(DependencyObject obj)

{

var list = new List<DependencyObject>() { obj };

var res = obj;

while ((res = GetParent(res)) != null)

list.Add(res);

return list.AsEnumerable().Reverse();

}

DependencyObject GetParent(DependencyObject obj)

{

var ff = obj as FrameworkElement;

if (ff != null)

return ff.Parent;

return null;

}

一个完整的代码:

主界面XAML:

<Grid>

<Grid.ColumnDefinitions>

<ColumnDefinition/>

<ColumnDefinition/>

</Grid.ColumnDefinitions>

<Grid.RowDefinitions>

<RowDefinition Height="auto"/>

<RowDefinition/>

</Grid.RowDefinitions>

<TextBlock>Logical Tree</TextBlock>

<TextBlock Grid.Column="1">Visual Tree</TextBlock>

<ListBox Name="lbxLogical" Grid.Row="1"/>

<ListBox Name="lbxVisual" Grid.Row="1" Grid.Column="1"/>

</Grid>

然后将ListBox的Logical Tree和Visual Tree显示在界面上,在Page的Loaded事件上调用上面的方法:

private void Page_Loaded_1(object sender, RoutedEventArgs e)

{

lbxLogical.ItemsSource = GetLogicalTree(lbxLogical).Select(d => d.GetType().Name);

lbxVisual.ItemsSource = GetVisualTree(lbxVisual).Select(d => d.GetType().Name);

}

结果:

image

posted @ 2012-06-25 10:57  therockthe  阅读(715)  评论(0)    收藏  举报