Программный просмотр логического и визуального дерева
88WPF --- Шаблоны и пользовательские элементы управления WPF --- Программный просмотр логического и визуального дерева
Хотя анализ логического дерева окна во время выполнения — не слишком часто применяемое программное действие в 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. Можно также просмотреть детали любого элемента, отследить любые маршрутизируемые события, просмотреть и даже модифицировать свойства элементов.