WPF:TreeView绑定

namespace PostViewer
{
    using System.Collections.ObjectModel;
    using System.ComponentModel;

    /// <summary>
    /// 数据类型ViewModel.
    /// </summary>
    public class VmTviDataType : ITreeItem
    {
        private bool mIsExpanded = true;
        private bool mIsSelected;

        /// <summary>
        /// Initializes a new instance of the <see cref="VmTviDataType"/> class.
        /// </summary>
        /// <param name="type">类型.</param>
        public VmTviDataType()
        {
            this.TviDataList = new ObservableCollection<VmTviData>();
        }

        /// <inheritdoc/>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Gets or sets 元素名称.
        /// </summary>
        public string Header { get; protected set; }

        /// <summary>
        /// Gets or sets a value indicating whether Treeviewitem 展开.
        /// </summary>
        public bool IsExpanded
        {
            get
            {
                return this.mIsExpanded;
            }

            set
            {
                if (value != this.mIsExpanded)
                {
                    this.mIsExpanded = value;
                    this.OnPropertyChanged("IsExpanded");
                }
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether Treeviewitem 选中.
        /// </summary>
        public bool IsSelected
        {
            get
            {
                return this.mIsSelected;
            }

            set
            {
                if (value != this.mIsSelected)
                {
                    this.mIsSelected = value;
                    this.OnPropertyChanged("IsSelected");
                }
            }
        }

        /// <summary>
        /// Gets or sets 数据集合.
        /// </summary>
        public ObservableCollection<VmTviData> TviDataList { get; set; }

        /// <summary>
        /// 属性变更事件处理.
        /// </summary>
        /// <param name="v">属性名称.</param>
        protected void OnPropertyChanged(string v)
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(v));
        }
    }
}
// <copyright file="ITreeItem.cs" company="Xtech">
// Copyright (c) Xtech. All rights reserved.
// </copyright>

namespace PostViewer
{
    using System.ComponentModel;

    /// <summary>
    /// 树形控件接口.
    /// </summary>
    public interface ITreeItem : INotifyPropertyChanged
    {
        /// <summary>
        /// Gets or sets a value indicating whether 是否选中.
        /// </summary>
        bool IsSelected { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether 是否展开.
        /// </summary>
        bool IsExpanded { get; set; }

        /// <summary>
        /// Gets 元素显示名称.
        /// </summary>
        string Header { get; }
    }
}
<UserControl x:Class="PostViewer.UcProjectTree"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:PostViewer"
             mc:Ignorable="d" 
             d:DesignHeight="600" d:DesignWidth="300">
    <Grid>
        <TreeView ItemsSource="{Binding TviProjectTypes}">
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                    <Setter Property="HorizontalContentAlignment" Value="Center" />
                    <Setter Property="VerticalContentAlignment" Value="Center" />
                    <Setter Property="FontWeight" Value="Normal" />
                    <Style.Triggers>
                        <Trigger Property="IsSelected" Value="True" >
                            <Setter Property="FontWeight" Value="Bold" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </TreeView.ItemContainerStyle>
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type local:VmTviProjectType}" ItemsSource="{Binding TviDataTypes}">
                    <StackPanel Orientation="Horizontal" Margin="0 2 5 0">
                        <TextBlock Text="{Binding Header}"/>
                    </StackPanel>
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type local:VmTviDataType}" ItemsSource="{Binding TviDataList}">
                    <StackPanel Orientation="Horizontal" Margin="0 2 5 0">
                        <TextBlock Text="{Binding Header}" />
                    </StackPanel>
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type local:VmTviData}">
                    <StackPanel Orientation="Horizontal" Margin="0 2 5 0">
                        <Image Width="15" Height="15" Margin="0, 1, 0 ,0" Source="/PostViewer;component/Resources/tree_blue.png" />
                        <TextBlock Text="{Binding Header}" />
                        
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>
    </Grid>
</UserControl>
原文地址:https://www.cnblogs.com/xpvincent/p/9525365.html