コントロールの一覧を表示しよう　(VisualTreeHelperとLogicalTreeHelperの違い)　その①

WPFでコントロールの一覧を表示しようとすると、
VisualTreeHelperとLogicalTreeHelperというクラスがありますが、
両者の違いは何があるのか。
サンプルソースを作成して検証してみます。


# サンプルソース
## 一覧出力用ソース

```C#
    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

```C#
<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の両方を組み合わせるパターンも触れようと思います。