You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF层级树形视图实现求助:基于公司-部门-员工数据模型

问题描述

我在实现WPF TreeView时遇到了问题,现有如下数据模型:

public class FullCompany
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime DateOfFoundation { get; set; }
    public string LegalAddress { get; set; }
    public List<Posts> Posts { get; set; }
}
public class Posts
{
   public int Id { get; set; }
   public string Name { get; set; }
   public string Director { get; set; }
   public int OrganizationId { get; set; }
   public List<Employee> Employees { get; set; }
}

我已经从数据库获取到了该数据,但不知道如何构建公司→部门→员工的层级树形视图。我尝试编写了以下XAML代码,需要实现按钮折叠/展开功能,但查找示例后仍无法解决当前问题:

<TreeView  ItemsSource="{Binding FullCompanies}" Grid.Row="1" x:Name="MainTreeView" HorizontalAlignment="Stretch" Margin="10" VerticalAlignment="Stretch">

        <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="FontWeight" Value="Normal" />
                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="FontWeight" Value="Bold" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </TreeView.ItemContainerStyle>
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="200"/>
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <StackPanel Grid.Column="0">
                        <Label Content="{Binding Name}"/>
                        <TreeView ItemsSource="{Binding Posts}"  x:Name="SubTreeView" HorizontalAlignment="Stretch" Margin="10" VerticalAlignment="Stretch">
                            <TreeView.ItemTemplate>
                                <HierarchicalDataTemplate>
                                    <Grid>
                                        <StackPanel Grid.Column="0">
                                            <Label Content="{Binding Name}"/>
                                            <TreeView ItemsSource="{Binding Employees}"  x:Name="SubTreeView1" HorizontalAlignment="Stretch" Margin="10" VerticalAlignment="Stretch">
                                                <TreeView.ItemTemplate>
                                                    <HierarchicalDataTemplate>
                                                        <Label Content="{Binding FirstName}"/>
                                                    </HierarchicalDataTemplate>
                                                </TreeView.ItemTemplate>
                                            </TreeView>
                                        </StackPanel>
                                    </Grid>
                                </HierarchicalDataTemplate>
                            </TreeView.ItemTemplate>
                        </TreeView>
                    </StackPanel>
                    <StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
                        
                        
                    </StackPanel>
                </Grid>
            </HierarchicalDataTemplate>
            
        </TreeView.ItemTemplate>

    </TreeView>
解决方案

1. 修正数据模型,添加绑定属性

你的数据模型需要实现INotifyPropertyChanged接口,并添加IsExpanded、IsSelected属性——因为你在Style中绑定了这些属性,但原始模型没有提供:

public class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class FullCompany : BaseViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime DateOfFoundation { get; set; }
    public string LegalAddress { get; set; }
    public List<Posts> Posts { get; set; }

    private bool _isExpanded;
    public bool IsExpanded
    {
        get => _isExpanded;
        set
        {
            _isExpanded = value;
            OnPropertyChanged();
        }
    }

    private bool _isSelected;
    public bool IsSelected
    {
        get => _isSelected;
        set
        {
            _isSelected = value;
            OnPropertyChanged();
        }
    }
}

public class Posts : BaseViewModel
{
   public int Id { get; set; }
   public string Name { get; set; }
   public string Director { get; set; }
   public int OrganizationId { get; set; }
   public List<Employee> Employees { get; set; }

    private bool _isExpanded;
    public bool IsExpanded
    {
        get => _isExpanded;
        set
        {
            _isExpanded = value;
            OnPropertyChanged();
        }
    }

    private bool _isSelected;
    public bool IsSelected
    {
        get => _isSelected;
        set
        {
            _isSelected = value;
            OnPropertyChanged();
        }
    }
}

public class Employee : BaseViewModel
{
    public string FirstName { get; set; }

    private bool _isSelected;
    public bool IsSelected
    {
        get => _isSelected;
        set
        {
            _isSelected = value;
            OnPropertyChanged();
        }
    }
}

2. 重构TreeView的XAML结构

你当前嵌套TreeView的写法是错误的——WPF TreeView本身支持层级结构,只需通过HierarchicalDataTemplate的ItemsSource指定子级集合即可,无需嵌套TreeView控件:

<TreeView ItemsSource="{Binding FullCompanies}" 
          Grid.Row="1" 
          x:Name="MainTreeView" 
          HorizontalAlignment="Stretch" 
          Margin="10" 
          VerticalAlignment="Stretch">

    <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="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 Posts}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="200"/>
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <Label Content="{Binding Name}" />
                <!-- 自定义展开/折叠按钮 -->
                <StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
                    <Button Content="{Binding IsExpanded, Converter={StaticResource BoolToExpandCollapseConverter}}"
                            Command="{Binding ToggleExpandCommand}"
                            Width="80" Margin="5"/>
                </StackPanel>
            </Grid>

            <!-- 部门层级模板 -->
            <HierarchicalDataTemplate.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Employees}">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="200"/>
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <Label Content="{Binding Name}" />
                        <StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
                            <Button Content="{Binding IsExpanded, Converter={StaticResource BoolToExpandCollapseConverter}}"
                                    Command="{Binding ToggleExpandCommand}"
                                    Width="80" Margin="5"/>
                        </StackPanel>
                    </Grid>

                    <!-- 员工层级模板 -->
                    <HierarchicalDataTemplate.ItemTemplate>
                        <DataTemplate>
                            <Label Content="{Binding FirstName}" />
                        </DataTemplate>
                    </HierarchicalDataTemplate.ItemTemplate>
                </HierarchicalDataTemplate>
            </HierarchicalDataTemplate.ItemTemplate>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

3. 添加转换器和命令实现自定义折叠/展开按钮

布尔值转文本转换器

用于根据展开状态切换按钮文本:

public class BoolToExpandCollapseConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (bool)value ? "折叠" : "展开";
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

在XAML资源中声明转换器:

<Window.Resources>
    <local:BoolToExpandCollapseConverter x:Key="BoolToExpandCollapseConverter"/>
</Window.Resources>

在BaseViewModel中添加切换命令

用于按钮触发展开/折叠操作:

public class BaseViewModel : INotifyPropertyChanged
{
    // 之前的INotifyPropertyChanged代码...

    public ICommand ToggleExpandCommand => new RelayCommand(ToggleExpand);

    private void ToggleExpand()
    {
        IsExpanded = !IsExpanded;
    }

    // 基础RelayCommand实现
    public class RelayCommand : ICommand
    {
        private readonly Action _execute;
        private readonly Func<bool> _canExecute;

        public event EventHandler CanExecuteChanged;

        public RelayCommand(Action execute, Func<bool> canExecute = null)
        {
            _execute = execute ?? throw new ArgumentNullException(nameof(execute));
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter) => _canExecute?.Invoke() ?? true;

        public void Execute(object parameter) => _execute();

        public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
}

关键说明

  • 禁止嵌套TreeView:WPF TreeView通过HierarchicalDataTemplate自动构建层级,嵌套TreeView会导致样式和交互混乱。
  • 必须实现INotifyPropertyChanged:确保UI能响应属性变化,比如IsExpanded改变时视图自动更新。
  • 自定义按钮通过命令绑定:手动控制展开/折叠状态,配合转换器实现按钮文本动态切换。

内容的提问来源于stack exchange,提问作者Alexandr Gevorkyan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 09:40:25