WPF中TabControl第二个TabItem内的DataGrid触发索引越界错误
问题原因
WPF 的 TabControl 存在默认的延迟渲染机制:只有当前处于选中状态的 TabItem 会在窗口初始化时完整构建内部的可视化树,未选中的 TabItem 内部控件的 UI 初始化、列生成等逻辑会被暂停,直到该 TabItem 第一次被用户选中才会执行。
你遇到索引越界的核心原因是:
- 第一个Tab默认处于选中状态,窗口
ContentRendered事件触发时,内部DataGrid已经完成UI初始化,给ItemsSource赋值后会立即触发自动列生成,Columns集合已填充,所以访问索引0正常。 - 第二个Tab初始未选中,哪怕你提前给DataGrid的
ItemsSource赋值了数据,UI层的自动列生成逻辑还没执行,Columns集合此时是空的,访问索引0就会触发越界错误。
你看到ItemsSource有数据是数据层的状态,和UI层的Columns集合填充是两个独立的流程,后者受TabControl延迟渲染的影响。
解决方案
推荐使用DataGrid的AutoGeneratedColumns事件处理列操作,该事件会在所有自动列生成完成后触发,不受TabControl延迟渲染的影响:
步骤1:修改XAML绑定事件
<TabControl x:Name="tabControl"> <TabItem x:Name="FirstTabItem" Header="First"> <DataGrid x:Name="datagridServicesFirstTab"> </DataGrid> </TabItem> <TabItem x:Name="SecondTabItem" Header="Second"> <!-- 绑定自动列生成完成事件 --> <DataGrid x:Name="datagridServices" AutoGeneratedColumns="datagridServices_AutoGeneratedColumns" > </DataGrid> </TabItem> </TabControl>
步骤2:拆分后台逻辑
// 窗口渲染完成后只赋值ItemsSource,不操作列 private void Window_ContentRendered(object sender, EventArgs e) { LoadServices(); } private void LoadServices() { if (serviceData.GetAllServices(currentID) != null) { datagridServices.ItemsSource = serviceData.GetAllServices(currentID).DefaultView; } } // 自动列生成完成后再操作列,不会出现越界 private void datagridServices_AutoGeneratedColumns(object sender, EventArgs e) { if (datagridServices.Columns.Count > 0) { datagridServices.Columns[0].Visibility = Visibility.Hidden; } }
可选替代方案
如果需要提前完成第二个Tab的初始化,可以在窗口加载时临时切换Tab选中状态触发渲染,不过该方案不如事件方案优雅,不推荐:
private void Window_ContentRendered(object sender, EventArgs e) { // 临时切换选中第二个Tab触发渲染 tabControl.SelectedItem = SecondTabItem; tabControl.SelectedItem = FirstTabItem; LoadServices(); // 此时第二个Tab的DataGrid已经完成初始化,操作列不会越界 datagridServices.Columns[0].Visibility = Visibility.Hidden; }
内容的提问来源于stack exchange,提问作者MS-Stack
相关产品推荐
相关产品推荐

