代码后台绑定DataTable时WPF DataGrid仅部分更新的问题
问题:WPF动态列DataGrid自定义单元格显示异常
场景说明
我有一个带DataGrid的WPF窗口,列数仅在运行时确定,要求每个单元格都显示自定义用户控件PathLossCell。
相关代码
窗口XAML中的DataGrid代码
<DataGrid Name="pathLossGrid" AutoGenerateColumns="True" ItemsSource="{Binding }" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" HorizontalAlignment="Center" GridLinesVisibility="All"> <DataGrid.Columns> <DataGridTemplateColumn> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <local:PathLossCell/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
窗口代码隐藏中的依赖属性
public static DependencyProperty PathLossTableProperty = DependencyProperty.Register(nameof(PathLossTable), typeof(DataTable), typeof(PathLossSelector)); public DataTable PathLossTable { get => (DataTable)GetValue(PathLossTableProperty); set => SetValue(PathLossTableProperty, value); }
自定义用户控件PathLossCell的XAML
<Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="0.8*"/> <ColumnDefinition Width="0.2*"/> </Grid.ColumnDefinitions> <TextBox Grid.Column="0" Text="{Binding S2pId }" MinWidth="50"/> <Button Grid.Column="1" Margin="3 0 0 0" Command="{Binding SelectS2pFileCommand}"> <Viewbox Stretch="Uniform"> <ContentControl Content="{DynamicResource icon_plus}"/> </Viewbox> </Button> </Grid>
DataTable初始化方法
public void InitPathLossTable() { if (PathLossTable == null && SelectedPortList != null) { var tmpTable = new DataTable("pathLossTable"); foreach (var port in SelectedPortList) { var portLoss = 0; DataColumn newColumn = new DataColumn($"{port} (Max Loss= {portLoss} dB)"); newColumn.DataType = typeof(PathLossCell); tmpTable.Columns.Add(newColumn); } //添加默认行 DataRow newRow = tmpTable.NewRow(); for (int col = 0; col < tmpTable.Columns.Count; col++) { newRow[col] = new PathLossCell() { S2pFile = "no data", RowId = 0, ColumnId = col, PortName = tmpTable.Columns[col].ColumnName }; } tmpTable.Rows.Add(newRow); PathLossTable = tmpTable; pathLossGrid.DataContext = PathLossTable.DefaultView; } }
异常现象
预期应显示对应列数的网格,且每个单元格都显示PathLossCell控件,但实际运行时:
- 仅[0,0]位置的单元格正常显示
PathLossCell控件 - 其余单元格显示
PathLossCell的完全限定类型字符串 - 网格额外多了一行空行
已尝试的操作
- 在XAML中直接设置
ItemsSource="{Binding PathLossTable.DefaultView}",无明显变化 - 移除
DataGridTemplateColumn定义后,首列也不再显示PathLossCell
修复尝试后的情况
将DataGrid.Columns模板替换为DataGrid.CellStyle后,所有单元格都显示了PathLossCell控件,但列头丢失,且控件数据绑定异常(仅显示控件框架,无对应数据)。
解决思路建议
1. 统一自动生成列的模板绑定
当AutoGenerateColumns="True"时,手动定义的DataGridTemplateColumn仅会作用于第一列,其余自动生成的列会默认调用对象的ToString()方法显示文本。需要通过AutoGeneratingColumn事件为每一列指定统一的单元格模板:
首先在窗口资源中预定义模板:
<Window.Resources> <DataTemplate x:Key="PathLossCellTemplate"> <local:PathLossCell DataContext="{Binding }"/> </DataTemplate> </Window.Resources>
然后绑定AutoGeneratingColumn事件并替换列模板:
private void pathLossGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) { var templateColumn = new DataGridTemplateColumn(); templateColumn.Header = e.Column.Header; templateColumn.CellTemplate = (DataTemplate)FindResource("PathLossCellTemplate"); e.Column = templateColumn; }
2. 修正DataTable的设计逻辑
不建议直接将UI控件PathLossCell作为DataTable的列类型,DataTable应存储数据模型而非控件实例,遵循UI与数据分离原则:
定义数据模型类:
public class PathLossData { public string S2pFile { get; set; } public int RowId { get; set; } public int ColumnId { get; set; } public string PortName { get; set; } public ICommand SelectS2pFileCommand { get; set; } }
修改DataTable初始化逻辑,将列类型改为数据模型:
// 替换原列类型定义 newColumn.DataType = typeof(PathLossData); // 初始化行时存入数据模型而非控件 newRow[col] = new PathLossData() { S2pFile = "no data", RowId = 0, ColumnId = col, PortName = tmpTable.Columns[col].ColumnName, SelectS2pFileCommand = yourCommandInstance // 传入实际命令实例 };
3. 关闭自动新增行功能
额外空行是DataGrid默认提供的新增数据行,设置CanUserAddRows="False"即可关闭:
<DataGrid Name="pathLossGrid" ... CanUserAddRows="False">
4. 修正绑定属性名
检查PathLossCell中的绑定属性,原代码绑定的S2pId与数据模型中的S2pFile不匹配,需统一:
<TextBox Grid.Column="0" Text="{Binding S2pFile }"/>
内容的提问来源于stack exchange,提问作者D.S.
相关产品推荐
相关产品推荐

