본문 바로가기

Dev::DotNet/WPF

WPF Visual Tree or Logical Tree 순회


WPF 에서는 

Logical Tree 와 Visual Tree 가 있다.


자세한 개념은 MSDN 이 가장 잘 설명해 놓았다.

(http://msdn.microsoft.com/ko-kr/library/ms753391.aspx)


쉽게 이야기 하면

어떤 "UI요소" 가 구성된 하위의 구조를 이야기 한다.


하나의 UI요소 는  다른 여러 UI요소들로 구성되어 있고

UI요소의 Template 안에는 이 UI요소 를 표현하는 여러 UI요소 가 들어있다.


TextBox 가 하나 있다면 


<TextBox />


TextBox  의 Template 에는 여러 UI요소들이 TextBox 의 모양을 구성하고 있다.


<ControlTemplate x:Key="TextBoxBaseControlTemplate1" TargetType="{x:Type TextBoxBase}">

            <Themes:ListBoxChrome x:Name="Bd" 

BorderBrush="{TemplateBinding BorderBrush}" 

BorderThickness="{TemplateBinding BorderThickness}" 

Background="{TemplateBinding Background}" 

RenderMouseOver="{TemplateBinding IsMouseOver}" 

RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" SnapsToDevicePixels="True">

                <ScrollViewer x:Name="PART_ContentHost" 

 SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>

            </Themes:ListBoxChrome>

            <ControlTemplate.Triggers>

                <Trigger Property="IsEnabled" Value="False">

                    <Setter Property="Background" TargetName="Bd" 

 Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>

                    <Setter Property="Foreground" 

 Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>

                </Trigger>

            </ControlTemplate.Triggers>

        </ControlTemplate>



Template 은 WPF 의 가장 기본적인 내용이다.



이런 윈도우를 구성해보았다.



<Window x:Class="SampleLogicalTree.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:My="clr-namespace:SampleLogicalTree"

        Title="MainWindow" Height="350" Width="525">

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition />

            <RowDefinition />

            <RowDefinition />

        </Grid.RowDefinitions>

      

        <Button Grid.Row="0" Content="Button 1" Click="OnButtonClick"/>

       

        <Grid Grid.Row="1" Margin="5">

            <Grid.ColumnDefinitions>

                <ColumnDefinition />

                <ColumnDefinition />

                <ColumnDefinition />

            </Grid.ColumnDefinitions>

            <Button Grid.Column="0" Content="Button 2-1" />

            <Button Grid.Column="1" Content="Button 2-2" />

            <Button Grid.Column="2" Content="Button 2-3" />

        </Grid>

       

        <Button Grid.Row="2" Content="Button 3" />

       

    </Grid>

</Window>



이런 윈도우에 포함된 UI요소들을 트리로 나열한 것이 Logical Tree 이다.

<SampleLogicalTree.MainWindow>

  <System.Windows.Controls.Grid>

    <System.Windows.Controls.Button />

    <System.Windows.Controls.Grid>

      <System.Windows.Controls.Button />

      <System.Windows.Controls.Button />

      <System.Windows.Controls.Button />

    </System.Windows.Controls.Grid>

    <System.Windows.Controls.Button />

  </System.Windows.Controls.Grid>

</SampleLogicalTree.MainWindow>


그리고 각각의 UI요소 들이 그 안에 시각적인 표현을 위해서 구성된 하위 UI요소 까지 트리로 나열한 것이 Visual Tree 이다

<SampleLogicalTree.MainWindow>

  <System.Windows.Controls.Border>

    <System.Windows.Documents.AdornerDecorator>

      <System.Windows.Controls.ContentPresenter>

        <System.Windows.Controls.Grid>

          <System.Windows.Controls.Button>

            <Microsoft.Windows.Themes.ButtonChrome>

              <System.Windows.Controls.ContentPresenter>

                <System.Windows.Controls.TextBlock />

              </System.Windows.Controls.ContentPresenter>

            </Microsoft.Windows.Themes.ButtonChrome>

          </System.Windows.Controls.Button>

          <System.Windows.Controls.Grid>

            <System.Windows.Controls.Button>

              <Microsoft.Windows.Themes.ButtonChrome>

                <System.Windows.Controls.ContentPresenter>

                  <System.Windows.Controls.TextBlock />

                </System.Windows.Controls.ContentPresenter>

              </Microsoft.Windows.Themes.ButtonChrome>

            </System.Windows.Controls.Button>

            <System.Windows.Controls.Button>

              <Microsoft.Windows.Themes.ButtonChrome>

                <System.Windows.Controls.ContentPresenter>

                  <System.Windows.Controls.TextBlock />

                </System.Windows.Controls.ContentPresenter>

              </Microsoft.Windows.Themes.ButtonChrome>

            </System.Windows.Controls.Button>

            <System.Windows.Controls.Button>

              <Microsoft.Windows.Themes.ButtonChrome>

                <System.Windows.Controls.ContentPresenter>

                  <System.Windows.Controls.TextBlock />

                </System.Windows.Controls.ContentPresenter>

              </Microsoft.Windows.Themes.ButtonChrome>

            </System.Windows.Controls.Button>

          </System.Windows.Controls.Grid>

          <System.Windows.Controls.Button>

            <Microsoft.Windows.Themes.ButtonChrome>

              <System.Windows.Controls.ContentPresenter>

                <System.Windows.Controls.TextBlock />

              </System.Windows.Controls.ContentPresenter>

            </Microsoft.Windows.Themes.ButtonChrome>

          </System.Windows.Controls.Button>

        </System.Windows.Controls.Grid>

      </System.Windows.Controls.ContentPresenter>

      <System.Windows.Documents.AdornerLayer />

    </System.Windows.Documents.AdornerDecorator>

  </System.Windows.Controls.Border>

</SampleLogicalTree.MainWindow>



WPF 에서는 당연히 Logical Tree 와 Visual Tree 를 만들 수 있는 방법을 제공한다.


Logical Tree 를 가져올 수 있는 "LogicalTreeHelper" 와

System.Windows.LogicalTreeHelper

 



System.IO.File.WriteAllText(@"C:\\LogicalTree.TXT", GetLogicalTree(this/*대상 UI요소*/).ToString());

 

public XElement GetLogicalTree(Object obj)

{

    XElement myEl = null;

 

    if (obj is FrameworkElement)

    {

        FrameworkElement element = (FrameworkElement)obj;

 

        myEl = new XElement(element.GetType().ToString());

 

        System.Collections.IEnumerable children =                                         System.Windows.LogicalTreeHelper.GetChildren(element);

        foreach (Object child in children)

        {

            XElement childTree = GetLogicalTree(child);

 

            if (childTree != null)

                myEl.Add(childTree);

        }

    }

 

    return myEl;

}

 

 

Visual Tree 를 가져올 수 있는 "VisualTreeHelper" 를 

System.Windows.Media.VisualTreeHelper

 


System.IO.File.WriteAllText(@"C:\\VisualTree.TXT", GetVisualTree(this/*대상 UI요소*/).ToString());

 

public XElement GetVisualTree(Object obj)

{

    XElement myEl = null;

 

    if (obj is FrameworkElement)

    {

        FrameworkElement element = (FrameworkElement)obj;

 

        myEl = new XElement(element.GetType().ToString());

 

        for(int i = 0; i < System.Windows.Media.VisualTreeHelper.GetChildrenCount(element); i++)

        {

            XElement childTree =                     GetVisualTree(System.Windows.Media.VisualTreeHelper.GetChild(element, i));

 

            if (childTree != null)

                myEl.Add(childTree);

        }

    }

 

    return myEl;

}


제공하고 있다.


이렇게 하면 Logical & Visual Tree 를 얻을 수 있다.

(좀 편하게 위와 같은 문자열을 만들려고 "XElement"를 사용하였다.)


굉장히 중요한 개념이지만

어떻게 보면 별로 쓸때가 없을 것 같기도 하다.


하지만 알아두면 굉장히 유용하게 쓰일 때가 있다.




'Dev::DotNet > WPF' 카테고리의 다른 글

XmlnsDefinition 을 통한 namespace 매칭  (0) 2013.11.22
WPF 에서 DoEvents  (0) 2013.11.18
NetAdvantage XamDockManager 의 Splitter 고정  (0) 2013.11.08
WPF Filter ComboBox  (0) 2013.11.04
XAML 에서 StringFormat 으로 문자열 표시  (0) 2013.10.25