Программный просмотр логического и визуального дерева

88

Хотя анализ логического дерева окна во время выполнения — не слишком часто применяемое программное действие в WPF, стоит упомянуть, что в пространстве имен System.Windows определен класс по имени LogicalTreeHelper, который позволяет просматривать структуру логического дерева во время выполнения. Для иллюстрации связи между логическими деревьями, визуальными деревьями и шаблонами элементов управления создайте новое приложение WPF.

Модифицируйте разметку окна, чтобы она содержала два элемента управления Button и большой доступный только для чтения элемент TextBox с включенными линейками прокрутки. Воспользуйтесь IDE-средой для обработки события Click каждой кнопки. Ниже показана необходимая XAML-разметка:

<Grid>
   <Grid.RowDefinitions>
           <RowDefinition Height="auto"></RowDefinition>
           <RowDefinition></RowDefinition>
   </Grid.RowDefinitions>
   <StackPanel Margin="5" Orientation="Horizontal">
           <Button Name="Btn_visualTreeView" Padding="5" Margin="8,0,0,0"
                      Click="Btn_visualTreeView_Click">Визуальное дерево</Button>
           <GroupBox Margin="5">
                      <StackPanel>
                            <RadioButton Name="InTreeView" Margin="3" IsChecked="True">Показать в TreeView</RadioButton>
                            <RadioButton Name="InTextBox" Margin="3">Показать в TextBox</RadioButton>
                      </StackPanel>
           </GroupBox>
   </StackPanel>
   <TextBox Name="txt" Grid.Row="1" Margin="5" TextWrapping="Wrap"
               HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
               IsReadOnly="True" BorderBrush="#2f3bc5"></TextBox>
</Grid>
using System.Windows.Markup;
//...

public partial class MainWindow : Window
{
        public MainWindow()
        {
            InitializeComponent();
            tw.Name = "treeView";
            tw.BorderBrush = new SolidColorBrush(Colors.Blue);
            tw.BorderThickness = new Thickness(2.0);
            tw.Margin = new Thickness(5.0);
        }

        public void ShowLogicalTree(DependencyObject element)
        {
            // Очистить дерево
            tw.Items.Clear();
            // Начать обработку элементов
            ProcessElement(element, null);
        }

        private TreeView tw = new TreeView();
        
        // Новое диалоговое окно с элементом TreeView
        public void MyShowDialog()
        {
            Window win = new Window();
            win.Title = "LogicTreeDisplay";
            win.Height = 400;
            win.Width = 250;
 
            Grid grid = new Grid();

            IAddChild container = grid;
            container.AddChild(tw);

            container = win;
            container.AddChild(grid);
            ShowLogicalTree(this);

            win.ShowDialog();
        }

        public void ProcessElement(DependencyObject element, TreeViewItem previousItem)
        {
            TreeViewItem item = new TreeViewItem();
            item.Header = element.GetType().Name;
            item.IsExpanded = true;
            if (previousItem == null)
            {
                tw.Items.Add(item);
            }
            else
            {
                previousItem.Items.Add(item);
            }
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
            {
                ProcessElement(VisualTreeHelper.GetChild(element, i), item);
            }
        }

        private void Btn_visualTreeView_Click(object sender, RoutedEventArgs e)
        {
            if ((bool)InTreeView.IsChecked)
            {
                MyShowDialog();
            }
        }
}
Программный просмотр визуального дерева

Класс LogicalTreeHelper предлагает относительно небольшой набор методов, перечисленных ниже. Хотя эти методы могут иногда пригодиться, в большинстве случаев вместо них используются методы специфического FrameworkElement.

FindLogicalNode()

Ищет определенный элемент по имени, начиная с указанного, вниз по логическому дереву

BringIntoView()

Прокручивает элемент в область видимости (если он находится в прокручиваемом контейнере и в данный момент не виден). Метод FrameworkElement.BringIntoView() выполняет тот же трюк

GetParent()

Получает родительский элемент определенного элемента

GetChildren()

Получает дочерний элемент определенного элемента. Как известно, разные элементы поддерживают разные модели содержимого. Например, панели поддерживают множество дочерних элементов, а элементы управления содержимым — только один дочерний элемент. Однако метод GetChildren() абстрагирован от этого различия и работает с обоими типами элементов

Класс VisualTreeHelper предлагает несколько похожих методов — GetChildrenCount(), GetChild() и GetParent() — наряду с небольшим набором методов, предназначенных для выполнения низкоуровневого рисования. (Например, здесь есть методы для проверки попадания и проверки границ)

Класс VisualTreeHelper также предоставляет интересный способ исследования визуального дерева внутри приложения. С использованием метода GetChild() можно углубиться в визуальное дерево любого окна и отобразить его для наглядности. Это замечательное учебное пособие, не требующее ничего кроме порции рекурсивного кода.

Исследовать визуальное дерево другого приложения можно с помощью замечательной утилиты Snoop. Она позволяет просматривать визуальное дерево любого функционирующего приложения WPF. Можно также просмотреть детали любого элемента, отследить любые маршрутизируемые события, просмотреть и даже модифицировать свойства элементов.

Пройди тесты
Лучший чат для C# программистов