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

如何高效填充WPF DataGrid?去除ToList实现DbSet流式加载

问题描述

我使用WPF DataGrid展示数据,目前通过DbSet调用ToList()方法填充数据源,加载速度很慢。想知道能不能去掉ToList(),实现DbSet数据流式传输到DataGrid,避免一次性把所有数据加载到内存列表里。相关代码示例如下:

DB上下文代码

using MyNameSpace.Data.DataModels;
using Microsoft.EntityFrameworkCore;

namespace MyNameSpace.Data
{
    public class DB: DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder options_builder) {
            options_builder.UseSqlServer("Server=server;Database=database;TrustServerCertificate=true;Integrated Security=true");
        }

        public DbSet<Projects> Projects { get; set; }
    }
}

主窗口代码

using MyNameSpace.Data;
using MyNameSpace.Data.DataModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace MyNameSpace
{
    public partial class MainWindow : Window
    {
        List<Projects> projects = new List<Projects>();
        public MainWindow() {
            InitializeComponent();
        }

        private void RetrieveButton_Click(object sender, RoutedEventArgs e) {
            GetProjects();
        }

        public void GetProjects() {
            var db = new DB();
            projects = db.Projects.ToList();
            ProjectsDatagrid.ItemsSource = projects;
        }
    }
}
解决方案

完全可以去掉ToList()实现流式加载,核心是利用EF Core的延迟查询特性,配合WPF DataGrid的虚拟化机制,让数据按需加载,而非一次性全量入内存。

1. 直接绑定DbSet到DataGrid

DbSet本身是IQueryable<T>类型,支持延迟执行,无需转成List<T>就能直接绑定:

public void GetProjects()
{
    var db = new DB();
    // 直接绑定DbSet,跳过ToList()
    ProjectsDatagrid.ItemsSource = db.Projects;
}

这样EF Core不会一次性拉取所有数据,只有当DataGrid需要渲染某几行时,才会从数据库加载对应的数据——前提是你开启了DataGrid的虚拟化。

2. 开启DataGrid虚拟化(关键)

WPF DataGrid默认可能未启用虚拟化,必须开启才能实现真正的按需加载。在XAML中给DataGrid添加以下属性:

<DataGrid x:Name="ProjectsDatagrid"
          EnableRowVirtualization="True"
          VirtualizingStackPanel.VirtualizationMode="Recycling"
          EnableColumnVirtualization="True"/>
  • EnableRowVirtualization="True":只渲染可见区域的行,减少UI渲染压力
  • VirtualizationMode="Recycling":复用行容器,避免频繁创建销毁UI元素
  • EnableColumnVirtualization="True":如果列数量较多,开启列虚拟化进一步优化

3. 重要注意事项

  • DbContext生命周期管理:不要在方法内创建DbContext后立即销毁(比如原代码中GetProjects方法内的db会在方法结束后被回收),否则DataGrid后续加载数据时会报错。建议把DbContext声明为窗口级字段:
private DB _db;

public MainWindow()
{
    InitializeComponent();
    _db = new DB();
}

public void GetProjects()
{
    ProjectsDatagrid.ItemsSource = _db.Projects;
}

// 窗口关闭时释放DbContext
protected override void OnClosed(EventArgs e)
{
    base.OnClosed(e);
    _db.Dispose();
}
  • 避免触发全量加载:不要对_db.Projects调用Count()、ToList()这类会立即执行查询的方法,否则还是会一次性加载所有数据。
  • 超大数据量的替代方案:如果数据量极大,流式加载仍有压力,可以结合分页查询,用Skip()和Take()配合分页控件手动控制加载量:
// 示例:加载第1页,每页20条
ProjectsDatagrid.ItemsSource = _db.Projects.Skip(0).Take(20).ToList();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 20:33:10