WPFでTreeViewでデータバインドするサンプル

C# コンピュータ
C#

TreeViewでフォルダーを表現したいと思い試作してみます。

ファイル名:FolderItem.cs

using System.ComponentModel;
using Reactive.Bindings;

namespace TreeViewSample01;

public class FolderItem : INotifyPropertyChanged
{
    // INotifyPropertyChanged
    public event PropertyChangedEventHandler? PropertyChanged;
    protected virtual void OnPropertyChanged(string name) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    
    // コンストラクタ
    public FolderItem()
    {
        PropertyChanged += (s, e) => {};        
    }
    // 名前
    public ReactiveProperty<string> Name { get; set; } = new("");
    // サブフォルダ
    public ReactiveCollection<FolderItem> SubFolders { get; set; } = new();

}

ファイル名:MainWindow.xaml

<Window
x:Class="TreeViewSample01.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:TreeViewSample01"
mc:Ignorable="d"
Height="450"
Width="800"
FontSize="24"
xmlns:i="clr-namespace:Microsoft.Xaml.Behaviors;assembly=Microsoft.Xaml.Behaviors">
  <Window.DataContext>
    <local:MainWindowViewModel />
  </Window.DataContext>
  <i:Interaction.Behaviors>
    <local:ViewModelCleanupBehavior />
  </i:Interaction.Behaviors>
  <Grid>
    <TreeView ItemsSource="{Binding Folders}">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding SubFolders}">
                <TextBlock Text="{Binding Name.Value}" />
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
  </Grid>
</Window>

ファイル名:MainWindowViewModel.cs

using System.Diagnostics;
using System.ComponentModel;
using Reactive.Bindings;
using Reactive.Bindings.Extensions;
using System.Reactive.Disposables;

namespace TreeViewSample01;
public class MainWindowViewModel : INotifyPropertyChanged, IDisposable
{
    // INotifyPropertyChanged
    public event PropertyChangedEventHandler? PropertyChanged;
    protected virtual void OnPropertyChanged(string name) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    // IDisposable
    private CompositeDisposable Disposable { get; } = [];

    /**************************************************************************
    * プロパティ
    **************************************************************************/
    public ReactiveCollection<FolderItem> Folders { get; set; } = [];

    public MainWindowViewModel()
    {
        PropertyChanged += (s, e) => {};

        var root = new FolderItem()
        {
            Name = new("/"),
        };
        Folders.AddOnScheduler(root);

        var folderUser = new FolderItem()
        {
            Name = new("Users"),
        };
        root.SubFolders.AddOnScheduler(folderUser);

        var folderBin = new FolderItem()
        {
            Name = new("Bin"),
        };
        folderUser.SubFolders.AddOnScheduler(folderBin);

        var folderHome = new FolderItem()
        {
            Name = new("Home"),
        };
        root.SubFolders.AddOnScheduler(folderHome);

        var folderEtc = new FolderItem()
        {
            Name = new("Etc"),
        };
        root.SubFolders.AddOnScheduler(folderEtc);

    }
    public void Dispose()
    {
        Debug.WriteLine("Dispose()");
        Disposable.Dispose();
    }
}

実行スクリーンショット

TreeViewのノードには子要素が複数存在します。ノードをフォルダーと見立てると子要素はサブフォルダーに相当し、コレクションで用意することになります。

ViewModelにReactiveCollection<FolderItem>を用意し、xamlのTreeViewのItemsSourceとバインドしています。

さらに、FolderItemクラスにはNameプロパティとSubFoldersコレクションを用意し、xamlのHierarchicalDataTemplateのItemsSourceにSubFolders、TextBlockにName.Valueをバインドしています。

ViewModelのコンストラクタでツリーの構造を作成しています。

TreeViewが作成できることが確認できました。次はTreeView側のイベント関連について調べたいと思います。

コメント