WinUI中TabView新增TabItem并传递行数据的实现方案
问题描述
我是C#和WinUI新手,开发的应用中有一个包含固定TabItem的TabView,该固定TabItem内有一个SfDataGrid。双击DataGrid的任意行时会新建一个TabItem,现需根据双击的行填充新TabItem的内容,且切换标签时不能重新加载数据(避免覆盖已编辑内容)。目前找到的动态填充方案会覆盖之前的编辑内容,求具体实现方法。
现有代码
Tasks.xaml(包含TabView和SfDataGrid)
<TabView x:Name="Tabs" AddTabButtonClick="TabView_AddButtonClick" TabCloseRequested="TabView_TabCloseRequested" Loaded="TabView_Loaded" TabDroppedOutside="TabView_TabDroppedOutside" CanDragTabs="True"> <TabViewItem Header="Tasks" IsClosable="False"> <TabViewItem.IconSource> <SymbolIconSource Symbol="Home" /> </TabViewItem.IconSource> <Grid> <Grid> <DataGrid:SfDataGrid x:Name="DataGrid" AutoGenerateColumns="False" ItemsSource="{Binding}" ShowSortNumbers="True" AllowResizingColumns="True" AllowDraggingColumns="True" SelectionUnit="Row" CellDoubleTapped="DataGrid_CellDoubleTapped" AllowGrouping="True" ShowGroupDropArea="True" AllowFiltering="True" FilterRowPosition="FixedTop"> <DataGrid:SfDataGrid.Columns> <DataGrid:GridNumericColumn MappingName="ColumnId" HeaderText="ID" ColumnWidthMode="Auto" IsHidden="True"/> <DataGrid:GridNumericColumn MappingName="ColumnStatus" HeaderText="STATUS" ColumnWidthMode="Auto" ImmediateUpdateColumnFilter="True"/> <DataGrid:GridTextColumn MappingName="ColumnTaskNr" HeaderText="NR" ColumnWidthMode="Auto" ImmediateUpdateColumnFilter="True"/> <DataGrid:GridTextColumn MappingName="ColumnCustomerName" HeaderText="KUND" ColumnWidthMode="Auto" ImmediateUpdateColumnFilter="True"/> <DataGrid:GridTextColumn MappingName="ColumnCustomT2" HeaderText="GÄLLER" ColumnWidthMode="Auto" ImmediateUpdateColumnFilter="True"/> <DataGrid:GridTextColumn MappingName="ColumnTask" HeaderText="UPPDRAG" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" ImmediateUpdateColumnFilter="True"/> <DataGrid:GridDateColumn MappingName="ColumnCreatedDate" HeaderText="SKAPAT TIDPUNKT" ColumnWidthMode="Auto" ImmediateUpdateColumnFilter="True" FilterRowEditorType="Date"/> <DataGrid:GridNumericColumn MappingName="ColumnPriority" HeaderText="PRIORITET" ColumnWidthMode="Auto" ImmediateUpdateColumnFilter="True"/> <DataGrid:GridTextColumn MappingName="ColumnCustomT1" HeaderText="ATT GÖRA" ColumnWidthMode="Auto" ImmediateUpdateColumnFilter="True"/> <DataGrid:GridTextColumn MappingName="ColumnCustomerRef" HeaderText="KONTAKTPERSON" ColumnWidthMode="Auto" ImmediateUpdateColumnFilter="True"/> </DataGrid:SfDataGrid.Columns> </DataGrid:SfDataGrid> </Grid> </Grid> </TabViewItem> </TabView>
Tasks.xaml.cs(创建新标签的函数)
private void DataGrid_CellDoubleTapped(object sender, Syncfusion.UI.Xaml.DataGrid.GridCellDoubleTappedEventArgs e) { this.DataGrid.SelectedIndex = this.DataGrid.ResolveToRecordIndex(e.RowColumnIndex.RowIndex); int rowIndex = e.RowColumnIndex.RowIndex; int columnIndex = this.DataGrid.ResolveToGridVisibleColumnIndex(e.RowColumnIndex.ColumnIndex); var recordIndex = this.DataGrid.ResolveToRecordIndex(rowIndex); var record1 = this.DataGrid.View.Records.GetItemAt(recordIndex); var mappingName = this.DataGrid.Columns[columnIndex].MappingName; string TaskNr = record1.GetType().GetRuntimeProperty("ColumnTaskNr").GetValue(record1).ToString(); TabViewItem newItem = new TabViewItem(); newItem.Header = $"{TaskNr}"; newItem.IconSource = new Microsoft.UI.Xaml.Controls.SymbolIconSource() { Symbol = Symbol.Document }; Frame frame = new Frame(); frame.Navigate(typeof(TaskDetails)); newItem.Content = frame; Tabs.TabItems.Add(newItem); }
解决方案
核心思路是缓存页面实例+复用已打开标签,确保切换标签时不会重建页面、覆盖编辑内容。
1. 修改标签创建逻辑(Tasks.xaml.cs)
加入已存在标签检查,启用页面导航缓存,并传递选中的任务数据:
private void DataGrid_CellDoubleTapped(object sender, Syncfusion.UI.Xaml.DataGrid.GridCellDoubleTappedEventArgs e) { // 获取双击行对应的任务记录 var recordIndex = DataGrid.ResolveToRecordIndex(e.RowColumnIndex.RowIndex); var selectedTask = DataGrid.View.Records.GetItemAt(recordIndex); string taskNr = selectedTask.GetType().GetRuntimeProperty("ColumnTaskNr").GetValue(selectedTask).ToString(); // 检查是否已打开该任务的标签页,避免重复创建 var existingTab = Tabs.TabItems.OfType<TabViewItem>() .FirstOrDefault(tab => tab.Header.ToString() == taskNr); if (existingTab != null) { // 直接切换到已存在的标签 Tabs.SelectedItem = existingTab; return; } // 创建新标签页 var newTab = new TabViewItem { Header = taskNr, IconSource = new SymbolIconSource { Symbol = Symbol.Document }, IsClosable = true }; // 创建Frame并启用导航缓存,防止页面重建 var contentFrame = new Frame(); contentFrame.NavigationCacheMode = NavigationCacheMode.Required; // 导航时传递选中的任务数据 contentFrame.Navigate(typeof(TaskDetails), selectedTask); newTab.Content = contentFrame; Tabs.TabItems.Add(newTab); Tabs.SelectedItem = newTab; }
2. 修改TaskDetails页面(TaskDetails.xaml.cs)
只在首次导航时绑定数据,保留编辑状态:
public sealed partial class TaskDetails : Page { private object _taskData; // 保存任务数据引用,避免重复赋值覆盖编辑内容 public TaskDetails() { this.InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); // 仅在首次进入页面时赋值,后续切换回来不再重新绑定 if (_taskData == null && e.Parameter != null) { _taskData = e.Parameter; DataContext = _taskData; } } }
关键说明
- 导航缓存:
NavigationCacheMode.Required让Frame保留页面实例,切换标签时不会重新创建TaskDetails,自然不会覆盖已编辑内容。 - 标签复用:提前检查是否已打开对应任务的标签,避免重复创建,同时提升操作效率。
- 数据保留:TaskDetails页面持有任务数据的引用,绑定后编辑的是同一个对象(如果需要独立编辑副本,可以在传递数据时克隆对象,比如手动复制属性或使用对象映射工具)。
内容的提问来源于stack exchange,提问作者zyntrax
相关产品推荐
相关产品推荐

