public class VisualUtilities { private int indentDepth = 0; public void PrintVisualTree(Visual v) { string name = null; increaseIndent(); if (v is FrameworkElement) name = ((FrameworkElement) v).Name; print("Visual Type: " + v.GetType().ToString() + (name != null ? ", Name: " + name : "")); // recurse through the children for (int i = 0; i < VisualTreeHelper.GetChildrenCount(v); i++) { PrintVisualTree(VisualTreeHelper.GetChild(v, i)); } decreaseIndent(); } public void PrintLogicalTree(Object obj) { increaseIndent(); if (obj is FrameworkElement) { FrameworkElement fe = (FrameworkElement)obj; print("Logical Type: " + fe.GetType() + ", Name: " + fe.Name); // recurse through the children IEnumerable children = LogicalTreeHelper.GetChildren(fe); foreach (object child in children) { PrintLogicalTree(child); } } else { // stop recursing as we certainly can't have any more FrameworkElement children print("Logical Type: " + obj.GetType()); } decreaseIndent(); } private void print(String line) { string indent; StringBuilder builder = new StringBuilder(); for (int i = 0; i < indentDepth; i++) builder.Append("\t"); builder.Append(line); Console.WriteLine(builder); } private void increaseIndent() { indentDepth++; } private void decreaseIndent() { indentDepth--; } }
- PrintLogicalTree 메소드는 object를 파라미터로 받는다.
-
논리 트리의 엘리먼트는 FrameworkElement에서 확장 되었거나 다른 object 타입이기 때문이다.
- 재귀의 기본 케이스는 FrameworkElement가 아닌 객체이며, 이 경우 논리 자식들이 정의 되어 있지 않으므로 더이상 재귀 호출을 진행하지 않는다.
-
FrameworkElement에 "Name" 속성이 정의 되어 있고, , Visual에는 존재 하지 않는다. 그래서 시각 트리를 훌륭하게 출력하고 논리 자식들에게 이름을 부여하여 출력하기 위해서는 반드시 FrameworkElement로 캐스팅 해야 했다.
-
LogicalTreeHelper는 IEnumerable 객체를 반환하는 GetChildren 함수를 지원한다.
-
반면 VisualTreeHelper는 GetChildrenCount 함수와 카운트를 순회 하는 GetChild 함수를 사용 할 수 있다.
-
이들 API간의 본질적인 차이는 무엇일까?
-
마이크로소프트의 말을 빌리자면 이렇다. "아마 서로 다른 개발자가 코딩 했기 때문일 것이다."
The XAML layout:
<Window x:Class="Test.Window1" xmlns="http://schemas.microsoft.com/winfx/avalon/2005" xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005" Title="Test" > <Grid x:Name="myGrid"> <Button x:Name="button1" Click="Button1Clicked">Some Content</Button> </Grid> </Window>
And the C# code behind:
public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void Button1Clicked(object sender, RoutedEventArgs e) { VisualUtilities util = new VisualUtilities(); Console.WriteLine("Logical Tree:"); util.PrintLogicalTree(this); Console.WriteLine("Visual Tree:"); util.PrintVisualTree(this); } }
Logical Tree:
Logical Type: Test.Window1, Name:
Logical Type: System.Windows.Controls.Grid, Name: myGrid
Logical Type: System.Windows.Controls.Button, Name: button1
Logical Type: System.String
Visual Tree:
Visual Type: Test.Window1, Name:
Visual Type: System.Windows.Controls.Border, Name:
Visual Type: System.Windows.Controls.Grid, Name:
Visual Type: System.Windows.Documents.AdornerDecorator, Name:
Visual Type: System.Windows.Controls.ContentPresenter, Name:
Visual Type: System.Windows.Controls.Grid, Name: myGrid
Visual Type: System.Windows.Controls.Button, Name: button1
Visual Type: Microsoft.Windows.Themes.ButtonChrome, Name:Chrome
Visual Type: System.Windows.Controls.ContentPresenter, Name:
Visual Type: System.Windows.Controls.TextBlock, Name:
Visual Type: System.Windows.Documents.AdornerLayer, Name:
Visual Type: System.Windows.Controls.Primitives.ResizeGrip, Name: WindowResizeGrip
출처 : http://blog.lab49.com/archives/217
좀더 좋은 번역이 될만한 내용 있으시면 덧글 부탁드려요. ^^