LoginSignup
3
3

More than 5 years have passed since last update.

【WPF】DataGridでツリー表示を実現する

Last updated at Posted at 2017-12-05

概要

 WPF(C#)でツールを作成するにあたって、ツリー表示させる必要が出てきたため、そこで作成したサンプルコードを載せます。環境は以下の通りです。

  • Visual Studio 2017
  • NugetにPrism.Mvvmをインストール済み

 以下はツールのキャプチャ画像であり、行追加ボタンを押して生成した"天財女王"の左にあるトグルボタンで子階層の表示・非表示を切り替えます。
DataGridのツリー表示.png

ソースコード

MainWindow.xaml
<Window x:Class="DataGridTest.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:DataGridTest"
        mc:Ignorable="d"
        Title="MainWindow" x:Name="WindowDataGrid" Height="350" Width="525">

    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>

    <StackPanel>
        <Button Content="行追加" Click="Button_Click"/>
        <DataGrid Name="dataGrid" CanUserAddRows="False" AutoGenerateColumns="False" ItemsSource="{Binding Data}">
            <DataGrid.Columns>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ToggleButton Visibility="{Binding VisibleGroup}" IsChecked="{Binding IsOpen, UpdateSourceTrigger=PropertyChanged}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTextColumn Header="名前" Binding="{Binding Name}" />
                <DataGridTextColumn Header="年齢" Binding="{Binding Age}" />
            </DataGrid.Columns>
        </DataGrid>
    </StackPanel>
</Window>
MainWindow.xaml.cs
using System.Windows;

namespace DataGridTest
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        // 行追加ボタン押下処理
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var vm = this.DataContext as ViewModel;
            if (null == vm) { return; }

            // ツリー表示となるデータを追加する
            vm.Add(new Person(vm._dumpData, vm.Data) { Name = "天財女王", Age = 57, VisibleGroup = Visibility.Visible });
        }
    }
}

Person.cs
using Microsoft.Practices.Prism.Mvvm;
using System.Collections.ObjectModel;
using System.Windows;

namespace DataGridTest
{
    // DataGridに表示するデータ
    public class Person : BindableBase
    {
        private ObservableCollection<Person> _Child;
        private ObservableCollection<Person> _Parent;

        // 名前
        public string Name { get; set; }

        // 年齢
        private int _Age;
        public int Age
        {
            get => _Age;
            set
            {
                if (value < 0)
                {
                    MessageBox.Show("範囲外の値が設定されました。");
                    OnPropertyChanged("Age");
                }
                else
                {
                    SetProperty(ref _Age, value);
                }
            }
        }

        // 階層を展開するためのボタンの表示状態
        public Visibility VisibleGroup { get; set; } = Visibility.Collapsed;

        // 子階層を表示しているか否か
        private bool _IsOpen = false;
        public bool IsOpen
        {
            get => _IsOpen;
            set
            {
                _IsOpen = value;
                if (null != _Child)
                {
                    // 子階層があれば、表示/非表示に応じて、データを挿入/削除する
                    if (_IsOpen)
                    {
                        int index = _Parent.IndexOf(this) + 1;
                        foreach (Person item in _Child)
                        {
                            _Parent.Insert(index, item);
                        }
                    }
                    else
                    {
                        int index = _Parent.IndexOf(this) + 1;
                        foreach (Person item in _Child)
                        {
                            _Parent.RemoveAt(index);
                        }
                    }
                }
            }
        }

        public Person() { }

        // 子階層と親階層を設定する
        public Person(ObservableCollection<Person> child, ObservableCollection<Person> parent)
        {
            _Child = child;
            _Parent = parent;
        }
    }
}
ViewModel.cs
using Microsoft.Practices.Prism.Mvvm;
using System.Collections.ObjectModel;
using System.Windows;

namespace DataGridTest
{
    public class ViewModel : BindableBase
    {
        // 子階層用のデータ
        public ObservableCollection<Person> _dumpData = new ObservableCollection<Person>
        {
            new Person{Name=" 天財息子", Age=29},
            new Person{Name=" 天財娘", Age=27}
        };

        // 初期データ
        private ObservableCollection<Person> _Data = new ObservableCollection<Person>
        {
            new Person{Name="天財太郎", Age=19},
            new Person{Name="天財次郎", Age=17}
        };

        public ObservableCollection<Person> Data
        {
            get => _Data;
            set
            {
                SetProperty(ref _Data, value);
            }
        }

        public void Add(Person data)
        {
            Data.Add(data);
            Data[0].VisibleGroup = Visibility.Hidden;
        }
    }
}
3
3
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
3
3