技術をかじる猫

適当に気になった技術や言語、思ったこと考えた事など。

WPFのTreeViewいじってみた。

バインド対象のモデル。
やべ、C#は覚えてるけど、WPFは2年いじってないからほぼ忘れた(;・∀・)
ここ眺めながら必死に思い出す。

class ModelDataValue : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public ModelDataValue(ModelDataValue parent, string path)
    {
        if (!Directory.Exists(path))
            throw new ArgumentException("path not found :" + path, path);

        this.info = new DirectoryInfo(path);
        this.parentNode = parent;
        this.children = null;
    }

    private ModelDataValue parentNode;
    private DirectoryInfo info;
    private ReadOnlyCollection<ModelDataValue> children;
    private bool _isExpanded;
    private bool _isSelected;

    public string Name
    {
        get { return info.Name; }
    }

    public ModelDataValue Parent
    {
        get { return this.parentNode; }
    }

    public bool IsExpanded
    {
        get { return this._isExpanded; }
        set
        {
            if (this._isExpanded == value) return;
            this._isExpanded = value;
            this.OnPropertyChanged("IsExpanded");
        }
    }

    public bool HasNoChildren
    {
        get
        {
            return this.children == null;
        }
    }

    public bool IsSelected
    {
        get { return this._isSelected; }
        set
        {
            if (this._isSelected == value) return;
            this._isSelected = value;
            this.OnPropertyChanged("IsSelected");
        }
    }

    public ReadOnlyCollection<ModelDataValue> Children
    {
        get
        {
            this.CreateChildren();
            return this.children;
        }
    }

    private void CreateChildren()
    {
        if (this.HasNoChildren)
        {
            List<ModelDataValue> lists = new List<ModelDataValue>();
            foreach (var directoryInfo in this.info.GetDirectories())
            {
                lists.Add(new ModelDataValue(this, directoryInfo.FullName));
            }

            this.children = new ReadOnlyCollection<ModelDataValue>(lists);
        }
    }

    private void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            PropertyChangedEventArgs args
                = new PropertyChangedEventArgs(propertyName);
            this.PropertyChanged(this, args);
        }
    }
}

IsSelected と IsExpanded が似てるから、すっごくリファクタしたいけどとりあえず。
Children 初回アクセス時に、子要素を列挙するようにしてる。動的な追加とか知らん。


MXML はこんな感じで。

<Window x:Class="FileFolderPractice1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" Initialized="Window_Initialized">
    <Grid>
        <TreeView ItemsSource="{Binding Path=Children}" Height="Auto" Width="Auto" HorizontalAlignment="Left" Name="treeView1" VerticalAlignment="Top">
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <Setter Property="IsExpanded" Value="{Binding Path=IsExpanded, Mode=TwoWay}" />
                    <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
                    <Setter Property="FontWeight" Value="Normal" />
                    <Style.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="FontWeight" Value="Bold" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </TreeView.ItemContainerStyle>
            
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Path=Children}">
                    <TextBlock Text="{Binding Path=Name}" />
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
</Window>

で、MainWindow でルートを作る。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_Initialized(object sender, EventArgs e)
    {
        ModelDataValue model = new ModelDataValue(null, @"C:\");
        this.DataContext = model;
    }
}