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

代码后台绑定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.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 08:50:39