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

WPF:如何将含自定义类的DataTable绑定到DataGrid并自定义列

解决方案:自定义DataTable绑定DataGrid并实现单元格模板

问题背景

需要将包含自定义类std和statObj的DataTable绑定到WPF DataGrid,实现以下要求:

  1. 第一列(std类型)同时显示图片和名称
  2. 其余列(statObj类型)仅展示Version属性
  3. 所有列通过后台代码手动创建

步骤1:修改后台代码,手动创建列与模板

首先关闭DataGrid的自动列生成,然后分别为不同类型的列创建对应模板与绑定逻辑。

更新后的后台代码:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    #region Property Changed stuff
    public event PropertyChangedEventHandler? PropertyChanged;
    private void OnPropertyChanged(string property)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
    }
    #endregion

    private DataTable _dt;
    public DataTable dt
    {
        get { return _dt; }
        set
        {
            _dt = value;
            OnPropertyChanged(nameof(dt));
        }
    }

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;

        // 创建DataTable
        DataTable dt = new DataTable();
        dt.Columns.Add(new DataColumn("Standard", typeof(std)));
        dt.Columns.Add(new DataColumn("Stat1", typeof(statObj)));
        dt.Columns.Add(new DataColumn("Stat2", typeof(statObj)));
        dt.Columns.Add(new DataColumn("Stat3", typeof(statObj)));

        // 添加示例数据
        std _std = new std { Name = "Objeto1", Id = "1", Picture = "C:\\temp\\Raccoon\\Std\\Objects\\Atmo1ManageDialogAddon\\V1.0\\Common\\Picture.png", Version = "1.0.3.2" };
        statObj _stat1 = new statObj { Name = "Objeto1", Id = "1", Version = "1.0.3.2" };
        statObj _stat2 = new statObj { Name = "Objeto1", Id = "1", Version = "1.0.2.2" };
        statObj _stat3 = new statObj { Name = "Objeto1", Id = "1", Version = "1.0.1.2" };

        for (int i = 0; i < 3; i++)
        {
            DataRow row = dt.NewRow();
            row[0] = _std;
            row[1] = _stat1;
            row[2] = _stat2;
            row[3] = _stat3;
            dt.Rows.Add(row);
        }

        // 关闭自动列生成,手动创建列
        dtGrid.AutoGenerateColumns = false;
        // 第一列:std类型自定义模板
        CreateStdColumn(dtGrid);
        // 其余statObj类型列
        CreateStatColumn(dtGrid, "Stat1");
        CreateStatColumn(dtGrid, "Stat2");
        CreateStatColumn(dtGrid, "Stat3");

        // 设置数据源
        dtGrid.ItemsSource = dt.DefaultView;
        this.dt = dt;
    }

    // 创建std类型列的方法
    private void CreateStdColumn(DataGrid grid)
    {
        DataGridTemplateColumn stdColumn = new DataGridTemplateColumn();
        stdColumn.Header = "Standard";
        stdColumn.Width = new DataGridLength(200);

        // 构建单元格模板的控件树
        FrameworkElementFactory stackPanelFactory = new FrameworkElementFactory(typeof(StackPanel));
        stackPanelFactory.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);

        // 添加Image控件,绑定图片路径
        FrameworkElementFactory imageFactory = new FrameworkElementFactory(typeof(Image));
        imageFactory.SetBinding(Image.SourceProperty, new Binding("Standard.Picture"));
        imageFactory.SetValue(Image.WidthProperty, 30.0);
        imageFactory.SetValue(Image.HeightProperty, 30.0);
        stackPanelFactory.AppendChild(imageFactory);

        // 添加TextBlock控件,绑定名称
        FrameworkElementFactory textBlockFactory = new FrameworkElementFactory(typeof(TextBlock));
        textBlockFactory.SetBinding(TextBlock.TextProperty, new Binding("Standard.Name"));
        textBlockFactory.SetValue(TextBlock.MarginProperty, new Thickness(5, 0, 0, 0));
        textBlockFactory.SetValue(TextBlock.VerticalAlignmentProperty, VerticalAlignment.Center);
        stackPanelFactory.AppendChild(textBlockFactory);

        DataTemplate cellTemplate = new DataTemplate();
        cellTemplate.VisualTree = stackPanelFactory;
        stdColumn.CellTemplate = cellTemplate;

        grid.Columns.Add(stdColumn);
    }

    // 创建statObj类型列的方法
    private void CreateStatColumn(DataGrid grid, string columnName)
    {
        DataGridTextColumn statColumn = new DataGridTextColumn();
        statColumn.Header = columnName;
        // 绑定对应列的Version属性
        statColumn.Binding = new Binding($"{columnName}.Version");
        statColumn.Width = new DataGridLength(120);

        grid.Columns.Add(statColumn);
    }

    public class std
    {
        public string? Name { get; set; }
        public string? Picture { get; set; }
        public string? Version { get; set; }
        public string? Id { get; set; }
    }

    public class statObj
    {
        public string? Name { get; set; }
        public string? Version { get; set; }
        public string? Id { get; set; }
    }
}

步骤2:简化XAML代码

无需额外绑定设置,仅保留基础DataGrid定义即可:

<Window x:Class="Raccoon.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Raccoon"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <DataGrid x:Name="dtGrid" IsReadOnly="True"/>
    </Grid>
</Window>

关键说明

  • 关闭自动列生成:必须设置AutoGenerateColumns=false,否则WPF会自动生成默认列,覆盖手动创建的自定义列
  • 绑定路径规则:DataTable每行是DataRowView类型,绑定需使用列名.属性名的格式(如Standard.Name)
  • 图片路径处理:若本地图片加载异常,可添加绑定转换器将字符串路径转换为BitmapImage对象

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 02:19:55