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

WPF绑定TreeView切换TabControl标签时选中状态重置问题

问题解决:WPF TabControl切换时TreeView状态丢失

需要在模型中保存每个TreeView的选中项和展开项状态,因为TabControl默认会销毁非活动标签对应的内容模板实例,导致TreeView的临时状态(选中、展开)丢失。以下是具体实现方案:

1. 调整模型结构

为每个树形节点添加展开状态属性,同时让模型实现INotifyPropertyChanged以支持数据绑定更新:

TreeItemViewModel(树形节点模型)

using System.ComponentModel;
using System.Runtime.CompilerServices;

public class TreeItemViewModel : INotifyPropertyChanged
{
    private string _name;
    private bool _isExpanded;

    public string Name
    {
        get => _name;
        set { _name = value; OnPropertyChanged(); }
    }

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

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

扩展后的ProjectModel

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;

public class ProjectModel : INotifyPropertyChanged
{
    private string _name;
    private TreeItemViewModel _selectedTreeItem;
    private ObservableCollection<TreeItemViewModel> _structure;

    public string Name
    {
        get => _name;
        set { _name = value; OnPropertyChanged(); }
    }

    public ObservableCollection<TreeItemViewModel> Structure
    {
        get => _structure;
        set { _structure = value; OnPropertyChanged(); }
    }

    public TreeItemViewModel SelectedTreeItem
    {
        get => _selectedTreeItem;
        set { _selectedTreeItem = value; OnPropertyChanged(); }
    }

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

2. 修改XAML绑定

将TreeView的选中项、每个节点的展开状态与模型属性绑定:

<TabControl x:Name="tcTest" >
    <!-- TabControl Style -->
    <TabControl.Resources>
        <Style TargetType="TabItem" BasedOn="{StaticResource {x:Type TabItem}}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TabItem}">
                        <Grid SnapsToDevicePixels="true">
                            <Border Padding="8,3" BorderThickness="1,1,1,0"  Height="27" Background="CadetBlue" >
                                <DockPanel>
                                    <TextBlock Text="{Binding Name}" />
                                </DockPanel>
                            </Border>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <!-- 绑定TreeViewItem的展开状态 -->
        <Style TargetType="TreeViewItem">
            <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
        </Style>
    </TabControl.Resources>

    <!-- TabControl Content Template -->
    <TabControl.ContentTemplate>
        <DataTemplate>
            <StackPanel>
                <TreeView ItemsSource="{Binding Path=Structure}"
                          SelectedItem="{Binding SelectedTreeItem, Mode=TwoWay}">
                    <TreeView.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Name}" />
                        </DataTemplate>
                    </TreeView.ItemTemplate>
                </TreeView>
            </StackPanel>
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>

3. 更新初始化代码

用TreeItemViewModel替换原来的字符串集合:

using System.Collections.ObjectModel;

public ObservableCollection<ProjectModel> Projects = new ObservableCollection<ProjectModel>();

public MainWindow()
{
    InitializeComponent();

    Projects.Add(new ProjectModel
    {
        Name = "Test",
        Structure = new ObservableCollection<TreeItemViewModel>
        {
            new TreeItemViewModel { Name = "Item 1" },
            new TreeItemViewModel { Name = "Item 2" },
            new TreeItemViewModel { Name = "Item 3" },
            new TreeItemViewModel { Name = "Item 4" },
        }
    });
    Projects.Add(new ProjectModel
    {
        Name = "Help",
        Structure = new ObservableCollection<TreeItemViewModel>
        {
            new TreeItemViewModel { Name = "Item 5" },
            new TreeItemViewModel { Name = "Item 6" },
            new TreeItemViewModel { Name = "Item 7" },
            new TreeItemViewModel { Name = "Item 8" },
        }
    });

    tcTest.ItemsSource = Projects;
}

替代方案(不推荐)

如果不想修改模型,可以禁用TabControl的内容虚拟化,但会增加内存占用:

<TabControl x:Name="tcTest" VirtualizingStackPanel.IsVirtualizing="False">
    <!-- 原有内容 -->
</TabControl>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 11:10:40