WPFでコントロールの一覧を表示しようとすると、
VisualTreeHelperとLogicalTreeHelperというクラスがありますが、
両者の違いは何があるのか。
サンプルソースを作成して検証してみます。
サンプルソース
一覧出力用ソース
public class WPFControlUtility
{
/// <summary>
/// Visaul要素を出力
/// </summary>
/// <param name="tgt"></param>
public static void ShowVisualControls(DependencyObject tgt)
{
ShowVisualControl(tgt);
}
private static void ShowVisualControl(DependencyObject tgt, int position = 0)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(tgt); i++)
{
DependencyObject childObj = VisualTreeHelper.GetChild(tgt, i);
// ログ出力
ShowLog(childObj, position);
if (VisualTreeHelper.GetChildrenCount(childObj) > 0)
{
int nextPosition = position + 1;
ShowVisualControl(childObj, nextPosition);
}
}
}
/// <summary>
/// Logical要素を出力
/// </summary>
/// <param name="tgt"></param>
public static void ShowLogicalControls(DependencyObject tgt)
{
ShowLogicalControl(tgt);
}
private static void ShowLogicalControl(DependencyObject tgt,int position = 0)
{
if (tgt == null) return;
ShowLog(tgt, position);
foreach(var ctl in LogicalTreeHelper.GetChildren(tgt))
{
if(ctl is DependencyObject)
{
int nextPosition = position + 1;
ShowLogicalControl((DependencyObject)ctl, nextPosition);
}
}
}
/// <summary>
/// コントロールの情報を出力
/// </summary>
/// <param name="tgt"></param>
/// <param name="position"></param>
private static void ShowLog(DependencyObject tgt, int position = 0)
{
string tab = null;
string baseInfo = tgt.ToString();
for (int i = 0; i < position; i ++)
{
tab += "\t";
}
// 下記情報を出力
// 基本情報 : コンテンツ
Debug.WriteLine(tab + baseInfo);
}
}
解析対象のサンプル画面
MainWindow.xaml
<Window x:Class="WpfSampleApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfSampleApplication"
xmlns:PN="clr-namespace:PFW;assembly=PFW"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<PN:ChangePage x:Name="changePage" HorizontalAlignment="Center"/>
</Grid>
<Grid Grid.Row="1">
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Width="429">
<Button Content="国の天気情報" Height="20" Margin="10,0,0,0" Click="Button_Click"></Button>
<Button Content="各市町村の天気情報 " Height="20" Margin="10,15,0,15" Click="Button_Click_1" />
</StackPanel>
</Grid>
</Grid>
</Window>
ChangePage x:Name="changePage"については
カスタムコントロールを動的に切り替えて表示しています。
イメージとしては下記画像の上部です。
https://cl.ly/0N2n370M2j1p
ログ結果
では実際にログ出力させてみましょう。
ロジカル出力
WpfSampleApplication.MainWindow
System.Windows.Controls.Grid
System.Windows.Controls.RowDefinition
System.Windows.Controls.RowDefinition
System.Windows.Controls.Grid
PFW.ChangePage
System.Windows.Controls.Grid
System.Windows.Controls.UserControl
WpfSampleApplication.Samples.Cities.CitiesPage
System.Windows.Controls.Grid
System.Windows.Controls.RowDefinition
System.Windows.Controls.RowDefinition
System.Windows.Controls.Grid
System.Windows.Controls.RowDefinition
System.Windows.Controls.RowDefinition
System.Windows.Controls.StackPanel
PFW.PNLabel: 国
PFW.PNTextBox
PFW.PNDataGrid Items.Count:0
System.Windows.Controls.Grid
System.Windows.Controls.StackPanel
PFW.PNButton: 確定
System.Windows.Controls.Grid
System.Windows.Controls.StackPanel
System.Windows.Controls.Button: 国の天気情報
System.Windows.Controls.Button: 各市町村の天気情報
ビジュアル出力
System.Windows.Controls.Border
System.Windows.Documents.AdornerDecorator
System.Windows.Controls.ContentPresenter
System.Windows.Controls.Grid
System.Windows.Controls.Grid
PFW.ChangePage
System.Windows.Controls.Border
System.Windows.Controls.ContentPresenter
System.Windows.Controls.Grid
System.Windows.Controls.UserControl
System.Windows.Controls.Border
System.Windows.Controls.ContentPresenter
System.Windows.Controls.Grid
System.Windows.Controls.StackPanel
System.Windows.Controls.Button: 国の天気情報
System.Windows.Controls.Border
System.Windows.Controls.ContentPresenter
System.Windows.Controls.TextBlock
System.Windows.Controls.Button: 各市町村の天気情報
System.Windows.Controls.Border
System.Windows.Controls.ContentPresenter
System.Windows.Controls.TextBlock
System.Windows.Documents.AdornerLayer
VisualTreeHelperとLogicalTreeHelperの違い
両者の大まかな違いとしては
・LogicalTreeHelperはXAMLで定義された内容(論理ツリー)が表示
・VisualTreeHelperはコントロールの内部情報(ビジュアルツリー)まで表示
のようです。
一見VisualTreeHelperの情報量が多く感じられますが、
XAMLで定義されたカスタムパーツ(ChangePage)の内容までは表示されていません。
LogicalTreeHelperではカスタムパーツの論理ツリーまで表示されています。
ただしこちらは各パーツの子要素までは表示されません。
このあたりの違いを次の記事でもう少し踏み込んで解析したいと思います。
また、目的によってVisualTreeHelperとLogicalTreeHelperの両方を組み合わせるパターンも触れようと思います。