教你如何制作Silverlight Visual Tree Inspector

Silverlight中有Logic Tree和Visual Tree之分。比如在Xaml中定义了所有UI的logic结构,相当于模型。而运行时,显示的是UI的实际的物理结构。举个例子Button实际上是由更细粒度的UI如border和rectangle绘制成的。这里教大家制作一个 Inspector来动态检查Visual Tree的结构。先看一下实际效果(请按Inspect按钮):

效果不错,感觉有firebug的风范 :) 接下来看看关键技术。

  1. 高亮显示。很简单就是一个红色的Rectangle,当鼠标移动时把它放在当前UI Element的位置,设置相应的Position和Size就OK了。
  2. 如何获得UI的Visual Tree。使用VisualTreeHelper.GetChildrenCount(DependencyObject)可以获得所有Child Visual UI,通过VisualTreeHelper.GetChild(int)一一提取出来。最后递归调用所有子节点就可以反应出层次结构。
  3. 如何获得UI的坐标值。网上搜了一下发现UIElement.TransformToVisual可以办到。

感觉没啥更深奥的东西了,实际代码也就50行不到,你可以将左边栏换成自己的UserControl,检查一下他的Visual Tree是什么样子的(秉承个人博客的作风就是要精简巧妙,希望大家喜欢)

附赠源码:

XAML

  
    
< UserControl x:Class ="SilverlightTutorial.InspectorPage"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml" >

< Canvas x:Name ="LayoutRoot" >
< Grid Background ="Cornsilk" Height ="400" Width ="600" >
< Grid.ColumnDefinitions >
< ColumnDefinition Width ="*" />
< ColumnDefinition Width ="*" />
</ Grid.ColumnDefinitions >
< StackPanel >
< Button Content ="Button" Height ="23" Name ="button1" Width ="75" />
< TextBlock Height ="28" Name ="label1" Width ="120" Text ="1234" />
< ListBox Height ="100" Name ="listBox1" Width ="120" >
< ListBoxItem > 1 </ ListBoxItem >
< ListBoxItem > 2 </ ListBoxItem >
< ListBoxItem > 3 </ ListBoxItem >
< ListBoxItem >
< Button Content ="Button" Height ="23" Name ="button2" Width ="75" />
</ ListBoxItem >
</ ListBox >
</ StackPanel >
< Grid Grid.Column ="1" >
< Grid.RowDefinitions >
< RowDefinition Height ="25" />
< RowDefinition Height ="*" />
</ Grid.RowDefinitions >
< ToggleButton Content ="Inspect" HorizontalAlignment ="Center" Name ="btnInspect" />
< ScrollViewer VerticalScrollBarVisibility ="Auto" Grid.Row ="1" >
< TextBlock Name ="textBlock1" />
</ ScrollViewer >
</ Grid >
</ Grid >
< Rectangle Name ="rectHighlight" Stroke ="Red" Width ="100" Height ="100" StrokeThickness ="2" Visibility ="Collapsed" />
</ Canvas >
</ UserControl >

CS

  
    
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace SilverlightTutorial
{
public partial class InspectorPage : UserControl
{
public InspectorPage()
{
InitializeComponent();
MouseMove
+= new MouseEventHandler(Page_MouseMove);
MouseLeftButtonUp
+= (sender, args) =>
{
btnInspect.IsChecked
= false ;
rectHighlight.Visibility
= System.Windows.Visibility.Collapsed;
};
}

void Page_MouseMove( object sender, MouseEventArgs e)
{
var dpObj
= (e.OriginalSource as DependencyObject);
if (( bool )btnInspect.IsChecked == false || dpObj == null || dpObj == rectHighlight)
return ;

Inspect(dpObj);
if (dpObj is UIElement)
{
var elm
= (dpObj as UIElement);
var generalTransform
= elm.TransformToVisual( null );
var point
= generalTransform.Transform( new Point());
SetHightlight(point, elm.RenderSize);
}
}

void SetHightlight(Point point, Size size)
{
rectHighlight.Visibility
= System.Windows.Visibility.Visible;
Canvas.SetLeft(rectHighlight, point.X);
Canvas.SetTop(rectHighlight, point.Y);
rectHighlight.Width
= size.Width;
rectHighlight.Height
= size.Height;
}

void Inspect(DependencyObject dpObj)
{
var sbuf
= new StringBuilder();
Inspect(sbuf,
0 , dpObj);
textBlock1.Text
= sbuf.ToString();
}

void Inspect(StringBuilder sbuf, int level, DependencyObject dpObj)
{
sbuf.AppendLine(
new string ( ' ' , 3 * level) + dpObj.GetType().Name);
for ( int i = 0 ; i < VisualTreeHelper.GetChildrenCount(dpObj); i ++ )
{
Inspect(sbuf, level
+ 1 , VisualTreeHelper.GetChild(dpObj, i));
}
}
}
}

PS. 有空会陆续把自己搜集的Silverlight知识做成系列,希望大家支持。

你可能感兴趣的:(silverlight)