Avalonia中,使用DataTable类型作为DataGrid的ItemSource 数据源

1.描述

假设:后端查询返回的是一个DataTable类型的结果

问题:发现

复制代码
ExistingProductionInfoDgvItemSource = dt;

或者

复制代码
ExistingProductionInfoDgvItemSource = dt.DefaultView均无法显示数据。。。

绑定为DataView类型会显示一段奇怪的东西出来,这里忘记截图了

2.代码

2.1View

XML 复制代码
                        <DataGrid
                            x:Name="ExistingProductionInfoDgv"
                            SelectedItem="{Binding SelectedConfProduct, Mode=TwoWay}"
                            ItemsSource="{Binding ExistingProductionInfoDgvItemSource.DefaultView}"
                            PointerReleased="ExistingProductionInfoDgv_OnPointerReleased"
                            AutoGenerateColumns="False"
                            GridLinesVisibility="All"/>

2.2ViewModel 的绑定

cs 复制代码
    private DataTable _existingProductionInfoDgvItemSource = new DataTable();

    public DataTable ExistingProductionInfoDgvItemSource
    {
        get => _existingProductionInfoDgvItemSource;
        set
        {
            _existingProductionInfoDgvItemSource = value;
            NotifyChanged();
            // 数据-赋值 传递dt-value给View的后置代码
            // DataTableUpdated?.Invoke(this,value);
            DataTableUpdated?.Invoke(this, _existingProductionInfoDgvItemSource);
        }
    }

    // 数据更新事件(联动View生成列)--代码后置
    public event EventHandler<DataTable> DataTableUpdated;


//查询赋值
    #region 初始化查询-刷新

    //获取数据
    private void GetAllConf_Product()
    {
        try
        {
            var db = new DBHelperTest();
            var dtResult = db.GetAllConf_ProductDataTable(); // 数据库查询

            // 直接赋值,触发DataTableUpdated事件
            ExistingProductionInfoDgvItemSource = dtResult ?? new DataTable();
        }
        catch (Exception ex)
        {
            CustomMessageBoxView.ShowAsync("数据加载失败", $"错误:{ex.Message}");
        }
    }

    #endregion

2.3代码后置

cs 复制代码
    private ProductSettingViewModel _vm;

    public ProductSetting()
    {
        this.DataContext = new ProductSettingViewModel();

        InitializeComponent();

        this.PointerReleased += ProductSetting_OnPointerReleased;


        // 1. 绑定ViewModel
        // this.DataContext = new ProductSettingViewModel();
        _vm = new ProductSettingViewModel();
        DataContext = _vm;

        // 2. 订阅事件-执行列生成
        ExistingProductionInfoDgv.Loaded += ExistingProductionInfoDgv_Loaded;
    }

    #region 现有产品信息Dgv1生成列

    // 3. DataGrid加载完成后自动触发(核心:此时DataGrid一定非null)
    private void ExistingProductionInfoDgv_Loaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
    {
        // 订阅ViewModel的数据更新事件(数据就绪后生成列)
        _vm.DataTableUpdated += Vm_DataTableUpdated;

        // 初始数据生成:如果ViewModel已查询到数据,直接生成列
        if (_vm.ExistingProductionInfoDgvItemSource?.Rows.Count > 0)
        {
            GenerateColumns(_vm.ExistingProductionInfoDgvItemSource);
        }
    }

    // 4. 生成列的核心方法(仅View层处理,完全对应示例逻辑)
    private void GenerateColumns(DataTable dt)
    {
        // 清除旧列
        ExistingProductionInfoDgv.Columns.Clear();

        // 绑定数据源为DataView
        ExistingProductionInfoDgv.ItemsSource = dt.DefaultView;

        var columnNameMap = new Dictionary<string, string>
        {
            { "ID", "序号" },
            { "Name", "产品名称" },
            { "Code", "产品识别码" },
            { "SOP_BarcodeParam", "产品扫码参数" },
            { "SOP_PartParam", "零件追溯参数" },
            { "SOP_WorkParam", "工序作业参数" },
            { "ProgramNum", "图号识别起始位" },
            { "StartNum", "图号识别位数" },
            { "CodeNum", "产品型号" },
            { "OrderProductionCode", "生产用号" }
            // 后续需要添加其他字段映射,直接在这里加键值对即可
        };

        // 遍历列生成DataGrid列
        foreach (DataColumn col in dt.Columns)
        {
            // 3. 根据字段名获取显示名(如果没有匹配的映射,默认用原字段名)
            string displayHeader = columnNameMap.TryGetValue(col.ColumnName, out string name)
                ? name
                : col.ColumnName;

            DataGridColumn gridCol = col.DataType == typeof(bool)
                ? new DataGridCheckBoxColumn //创建复选框单元格
                {
                    Header = displayHeader,
                    Binding = new Binding($"Row.ItemArray[{col.Ordinal}]")
                }
                : new DataGridTextColumn //创建文本框单元格
                {
                    Header = displayHeader,
                    Binding = new Binding($"Row.ItemArray[{col.Ordinal}]")
                };

            ExistingProductionInfoDgv.Columns.Add(gridCol);
        }
    }

    // 5. 响应ViewModel的数据更新(数据变化时重新生成列)
    private void Vm_DataTableUpdated(object? sender, DataTable dt)
    {
        GenerateColumns(dt);
    }

    #endregion

3.效果

显示成功

4.修改

4.1过滤不需要的列

某一个表:

其中FieldName和FieldAttribute 是我不需要的数据库字段

在生成列的方法中:使用HashSet设定一组需要的列名,

// 1. 定义需要显示的列名(仅保留这三个)

var needShowColumns = new HashSet<string>

{

"ID",

"FieldDesc",

"FieldDataSource"

};

在声明列前使用if判断是否是需要的列即可

复制代码
// 过滤不需要的列
if (!needShowColumns.Contains(col.ColumnName))
{
    continue; // 不生成该列,直接进入下一次循环
}
cs 复制代码
  private void ProductSettingDgv_GenerateColumns(DataTable dt)
    {
        ProductSettingDgv.Columns.Clear();

        ProductSettingDgv.ItemsSource = dt.DefaultView;

        // 1. 定义需要显示的列名(仅保留这三个)
        var needShowColumns = new HashSet<string>
        {
            "ID",
            "FieldDesc",
            "FieldDataSource"
        };

        var columnNameMap = new Dictionary<string, string>()
        {
            { "ID", "序号" },
            { "FieldDesc", "参数名称" },
            { "FieldDataSource", "参数设定值" },
        };

        //遍历生成DataGrid列
        foreach (DataColumn col in dt.Columns)
        {
            // 过滤不需要的列
            if (!needShowColumns.Contains(col.ColumnName))
            {
                continue; // 不生成该列,直接进入下一次循环
            }

            //根据数据库字段名,获取,Dgv2的列名
            string displayHeader = columnNameMap.TryGetValue(col.ColumnName, out string name)
                ? name
                : col.ColumnName;
            //判断列的类型 ?复选框:文本

            DataGridColumn gridcol = col.DataType == typeof(bool)
                ? new DataGridCheckBoxColumn
                {
                    Header = displayHeader,
                    Binding = new Binding($"Row.ItemArray[{col.Ordinal}]")
                }
                : new DataGridTextColumn
                {
                    Header = displayHeader,
                    Binding = new Binding($"Row.ItemArray[{col.Ordinal}]")
                };
            ProductSettingDgv.Columns.Add(gridcol);
        }
    }
相关推荐
凯子坚持 c10 小时前
【星光不负 码向未来 | 万字解析:基于ArkUI声明式UI与分布式数据服务构建生产级跨设备音乐播放器】
分布式·ui
切糕师学AI13 小时前
C# 使用 CSRedisCore指南
redis·c#·.net core
.生产的驴14 小时前
React 路由权限跳转 Token判断 路由控制 登录状态控制
前端·javascript·react.js·ajax·前端框架·c#·ecmascript
SunnyDays10111 天前
如何使用 C# 将 CSV 数据轻松转换为 PDF
c#·csv转pdf
Big_潘大师1 天前
C# 六自由度机械臂正反解计算
数学建模·机器人·c#·六自由度机械臂
我不是程序猿儿1 天前
【C#】XtraMessageBox(DevExpress)与MessageBox(WinForms 标准库)的区别
开发语言·c#
偶尔的鼠标人1 天前
Avalonia/WPF 打开子窗口,并且跨页面传值
c#·wpf·mvvm·avalonia
玖笙&1 天前
✨WPF编程进阶【6.1】:图形原则(附源码)
c++·c#·wpf·visual studio
huoshan123451 天前
给旧版 .NET 也开一扇“私有之门”——ILAccess.Fody 实现原理与设计
c#·.net·fody·il·mono.cecil
纸照片1 天前
WPF中为Button设置IsMouseOver和IsPressed事件中改变背景颜色不起作用
c#·.net·wpf