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

WPF TabControl切换时DataGrid绑定数据错乱问题求助

WPF TabControl切换标签页后DataGrid绑定数据错乱问题

在TabControl中包含两个DataGrid,分别对应“Files”和“Symbols”标签页。切换到“Symbols”标签页后再切回“Files”时,Files DataGrid的显示模板正确,但加载的却是Symbols的数据,仿佛两个DataGrid的绑定在切换标签时发生了交换。尝试过在切换标签时强制设置当前显示DataGrid的ItemSource作为临时解决方法,但会导致行项断开关联。

相关代码

XAML代码

<TabControl Grid.Row="1" x:Name="tabsControl" SelectionChanged="OnTabChanged_TabsControl">
 
    <TabItem x:Name="filesTab">
        <TabItem.HeaderTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Image Source="{DynamicResource FilesTabIcon}" Width="19" Height="19"/>
                    <TextBlock Text="Files" Margin="4,0,0,0" VerticalAlignment="Center"/>
                </StackPanel>
            </DataTemplate>
        </TabItem.HeaderTemplate>
        <Grid>
            <!-- data -->
            <DataGrid x:Name="filesDataGrid" ItemsSource="{Binding Files}" Style="{DynamicResource SearchDataGrid}" Sorting="OnDataSort_Files" SelectionMode="Single" AutoGenerateColumns="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10" IsReadOnly="True" Visibility="Collapsed">
                <DataGrid.Columns>
                    <DataGridTemplateColumn Header="Name" Width="auto" SortMemberPath="Name">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
                                    <Image Source="{Binding ImageSource}" Width="16" Height="16" Margin="0,0,4,0"/>
                                    <TextBlock Text="{Binding Name}" HorizontalAlignment="Stretch" MouseLeftButtonDown="OnClick_FilesItem"/>
                                </StackPanel>                                      
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn Header="Path" Width="*" SortMemberPath="Path">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                    <Button Click="OnClick_FileLink" ToolTip="Copy path to clipboard" Height="16" Width="25" Padding="0,-2,0,0" Style="{DynamicResource ButtonStyle}">
                                        <Image Source="{DynamicResource LinkImageResource}" Width="19" Height="19" Margin="0"/>
                                    </Button>
                                    <TextBlock Text="{Binding Path}" Margin="4,0,0,0" MouseLeftButtonDown="OnClick_FilesItem"/>
                                </StackPanel>                                        
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>                       
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    </TabItem>

    <TabItem x:Name="symbolsTab">
        <TabItem.HeaderTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Image Source="{DynamicResource SymbolsTabIcon}" Width="19" Height="19"/>
                    <TextBlock Text="Symbols" Margin="4,0,0,0" VerticalAlignment="Center"/>
                </StackPanel>
            </DataTemplate>
        </TabItem.HeaderTemplate>
        <Grid>
            <!-- data -->
            <DataGrid x:Name="symbolsDataGrid" ItemsSource="{Binding Symbols}" Style="{DynamicResource SearchDataGrid}" Sorting="OnDataSort_Symbols" SelectionMode="Single" AutoGenerateColumns="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10" IsReadOnly="True" Visibility="Collapsed">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="auto" SortMemberPath="Name"/>

                    <DataGridTemplateColumn Header="Name" Width="auto" SortMemberPath="Name">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
                                    <Button Click="OnClick_SymbolLink" ToolTip="Copy path to clipboard" Height="16" Width="25" Padding="0,-2,0,0" Style="{DynamicResource ButtonStyle}">
                                        <Image Source="{DynamicResource LinkImageResource}" Width="19" Height="19" Margin="0"/>
                                    </Button>
                                    <TextBlock Text="{Binding Path}" HorizontalAlignment="Stretch" Margin="4,0,0,0"  MouseLeftButtonDown="OnClick_SymbolsItem"/>
                                </StackPanel>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    </TabItem>

</TabControl>

后台代码

public partial class MyControl : UserControl, INotifyPropertyChanged
{
   private List<SearchDataItem> _files = null;
   public List<SearchDataItem> Files
   {
       get { return _files; }
       set
       {
           if (_files != value)
           {
               _files = value;
               OnPropertyChanged(nameof(Files));
           }
       }
   }

   private List<SearchDataItem> _symbols = null;
   public List<SearchDataItem> Symbols
   {
       get { return _symbols; }
       set
       {
           if (_symbols != value)
           {
               _symbols = value;
               OnPropertyChanged(nameof(Symbols));
           }
       }
   }

   public event PropertyChangedEventHandler PropertyChanged;
   protected virtual void OnPropertyChanged(string propertyName)
   {
       PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
   }

   public FilesSearchControl()
   {
       this.InitializeComponent();
       DataContext = this;  // make sure the DC is set to this object
   }

   ...
}

问题原因

WPF TabControl默认会对未激活的TabItem进行虚拟化处理(延迟加载或卸载内容),当切换标签时,可能因DataTemplate复用、绑定上下文共享导致数据绑定错乱。加上两个DataGrid使用相同类型的数据源,进一步加剧了这个问题。

解决方法

1. 为每个TabItem显式隔离DataContext

避免TabItem之间共享绑定上下文,给每个TabItem的容器单独设置DataContext,确保绑定独立性:

<TabItem x:Name="filesTab">
    <TabItem.HeaderTemplate>
        <!-- 原有HeaderTemplate内容 -->
    </TabItem.HeaderTemplate>
    <Grid DataContext="{Binding}">
        <!-- 原有filesDataGrid内容 -->
    </Grid>
</TabItem>

<TabItem x:Name="symbolsTab">
    <TabItem.HeaderTemplate>
        <!-- 原有HeaderTemplate内容 -->
    </TabItem.HeaderTemplate>
    <Grid DataContext="{Binding}">
        <!-- 原有symbolsDataGrid内容 -->
    </Grid>
</TabItem>

2. 禁用TabControl虚拟化

强制TabControl加载所有TabItem内容,避免卸载导致的绑定问题,适合TabItem数量较少的场景:

<TabControl Grid.Row="1" x:Name="tabsControl" SelectionChanged="OnTabChanged_TabsControl"
            VirtualizingPanel.IsVirtualizing="False">
    <!-- 原有TabItem内容 -->
</TabControl>

3. 改用ObservableCollection作为数据源

List<T>不会自动通知UI数据变化,替换为ObservableCollection<T>可提升绑定可靠性:

private ObservableCollection<SearchDataItem> _files = new ObservableCollection<SearchDataItem>();
public ObservableCollection<SearchDataItem> Files
{
    get { return _files; }
    set
    {
        if (_files != value)
        {
            _files = value;
            OnPropertyChanged(nameof(Files));
        }
    }
}

private ObservableCollection<SearchDataItem> _symbols = new ObservableCollection<SearchDataItem>();
public ObservableCollection<SearchDataItem> Symbols
{
    get { return _symbols; }
    set
    {
        if (_symbols != value)
        {
            _symbols = value;
            OnPropertyChanged(nameof(Symbols));
        }
    }
}

4. 优化SelectionChanged事件的临时方案

如果要保留强制设置ItemSource的方式,先置空再重新赋值,避免绑定复用旧引用:

private void OnTabChanged_TabsControl(object sender, SelectionChangedEventArgs e)
{
    if (tabsControl.SelectedItem == filesTab)
    {
        filesDataGrid.ItemsSource = null;
        filesDataGrid.ItemsSource = Files;
    }
    else if (tabsControl.SelectedItem == symbolsTab)
    {
        symbolsDataGrid.ItemsSource = null;
        symbolsDataGrid.ItemsSource = Symbols;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 17:49:58