LoginSignup
8
5

More than 5 years have passed since last update.

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

Posted at

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

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5