视觉画布设计
canvas-design
基于设计原则创作静态视觉作品,用于海报与品牌图形。
reogrid【文档与办公】Use when embedding an Excel-like spreadsheet control in .NET WinForms/WPF applications — formula engine, cell editing, clipboard, undo/redo. ReoGrid: .NET spreadsheet component with NPOI-based Excel read/write.
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
name: reogrid description: "Use when embedding an Excel-like spreadsheet control in .NET WinForms/WPF applications — formula engine, cell editing, clipboard, undo/redo. ReoGrid: .NET spreadsheet component with NPOI-based Excel read/write." tags:
项目地址: https://github.com/unvell/ReoGrid
NuGet:
unvell.ReoGrid.dll(WinForms 核心)、unvell.ReoGridWPF.dll(WPF)、unvell.ReoGrid8.dll(.NET 8 版)最新版本: unvell.ReoGrid.dll 3.3.1 / unvell.ReoGridWPF.dll 3.3.0 / unvell.ReoGrid8.dll 8.1.0(截至2026-09,NuGet)
许可证: MIT(V3 社区版);商业版另购(V4)
ReoGrid 主要能力:
ReoGrid 不依赖 Excel/COM,纯托管代码,跨 .NET Framework 与 .NET 6+。
# WinForms
dotnet add package unvell.ReoGrid.dll
# WPF
dotnet add package unvell.ReoGridWPF.dll
# .NET 8 版本(WinForms 核心)
dotnet add package unvell.ReoGrid8.dll
三个包内的程序集名均为
unvell.ReoGrid.dll,命名空间统一是unvell.ReoGrid.*。
using unvell.ReoGrid;
using unvell.ReoGrid.IO;
var grid = new ReoGridControl { Dock = DockStyle.Fill };
this.Controls.Add(grid);
var sheet = grid.CurrentWorksheet;
sheet["A1"] = "ID";
sheet["B1"] = "Name";
sheet["C1"] = "Score";
sheet["A2"] = 1;
sheet["B2"] = "Tom";
sheet["C2"] = 95;
<Window xmlns:rg="clr-namespace:unvell.ReoGrid;assembly=unvell.ReoGrid">
<rg:ReoGridControl x:Name="Grid"/>
</Window>
var sh = Grid.CurrentWorksheet;
sh["A1:C1"] = new object[] { "ID", "Name", "Score" };
sh["A2:C2"] = new object[] { 1, "Tom", 95 };
sh.SetRangeData("A2:C4", new object[,] {
{ 1, "Tom", 95 },
{ 2, "Lucy", 88 },
{ 3, "Mike", 72 },
});
object[,] data = (object[,])sh.GetRangeData("A2:C4");
sh.SetRangeStyles("A1:C1", new WorksheetRangeStyle {
Flag = PlainStyleFlag.All,
Bold = true,
BackColor = Color.LightGray,
HorizontalAlign = ReoGridHorAlign.Center,
VerticalAlign = ReoGridVerAlign.Middle,
TextColor = Color.Black,
FontSize = 12
});
// 数据格式(百分比 / 日期)
sh.SetRangeDataFormat("C2:C100", CellDataFormatFlag.Percent,
new NumberDataFormatter.NumberFormatArgs { DecimalPlaces = 2 });
sh.SetRangeDataFormat("D2:D100", CellDataFormatFlag.DateTime,
new DateTimeDataFormatter.DateTimeFormatArgs { Format = "yyyy-MM-dd" });
sh["C5"] = "=SUM(C2:C4)";
sh["C6"] = "=AVERAGE(C2:C4)";
sh["C7"] = "=IF(C2>90, \"A\", \"B\")";
sh.Recalculate(); // 强制重算
sh.MergeRange("A1:C1");
sh.FreezeToCell("A2");
sh.Cells["B2"].Comment = new Comment("张三是优秀员工");
sh.AddRangeDataValidation(new DataValidation(
new RangePosition("C2:C100"),
DataValidationType.WholeNumber, 0, 100));
sh.CreateAutoFilter("A1:C100");
grid.Load("input.xlsx", FileFormat.Excel2007);
grid.Save("output.xlsx", FileFormat.Excel2007);
grid.Save("data.csv", FileFormat.CSV);
sh.CellDataChanged += (s, e) =>
Debug.WriteLine(quot;{e.Cell.PositionAsString} 改为 {e.Cell.Data}");
sh.SelectionChanged += (s, e) => statusLabel.Text = e.Range.ToAddress();
using unvell.ReoGrid.Drawing;
using unvell.ReoGrid.Chart;
var chart = new LineChart {
Bounds = new Rectangle(300, 50, 400, 300),
Title = "成绩",
DataSource = new WorksheetChartDataSource(sh, "B1:B4", "C2:C4")
};
sh.FloatingObjects.Add(chart);
// 内嵌 JS
function autoFill(sheet) {
for (var i = 1; i < 10; i++) {
sheet["A" + (i+1)] = i;
sheet["B" + (i+1)] = i * 100;
}
}
grid.RunScript(@"autoFill(workbook.currentWorksheet);");
grid.Worksheets[0].PrintSettings = new PrintSettings {
PageOrientation = PageOrientation.Landscape,
Margins = new PageMargins(0.5f, 0.5f, 0.5f, 0.5f)
};
grid.Print(); // 调用打印对话框
grid.Save("report.pdf", FileFormat.PDF);
SetRangeData(...) 替代逐格赋值sh.SuspendUIUpdates() / sh.ResumeUIUpdates()Recalculate,由用户触发// 1. 创建控件并加载数据
var grid = new ReoGridControl { Dock = DockStyle.Fill };
this.Controls.Add(grid);
var sheet = grid.CurrentWorksheet;
// 2. 设置标题行样式
sheet.SetRangeStyles("A1:D1", new WorksheetRangeStyle {
Flag = PlainStyleFlag.All,
Bold = true,
BackColor = Color.LightGray,
HorizontalAlign = ReoGridHorAlign.Center,
});
// 3. 批量填充数据
sheet["A1:D1"] = new object[] { "ID", "姓名", "部门", "薪资" };
sheet.SetRangeData("A2:D100", dataArray); // 大批量用 SetRangeData
// 4. 添加汇总公式
sheet["D101"] = "=SUM(D2:D100)";
sheet["A101"] = "合计:";
sheet.MergeRange("A101:C101");
// 5. 冻结标题行 + 自动筛选
sheet.FreezeToCell("A2");
sheet.CreateAutoFilter("A1:D100");
// 6. 导出
grid.Save("report.xlsx", FileFormat.Excel2007);
// 1. 创建带验证的模板
sheet["A1:C1"] = new object[] { "日期", "项目", "金额" };
sheet.SetRangeStyles("A1:C1", new WorksheetRangeStyle { Bold = true });
// 2. 设置日期列格式
sheet.SetRangeDataFormat("A2:A100", CellDataFormatFlag.DateTime,
new DateTimeDataFormatter.DateTimeFormatArgs { Format = "yyyy-MM-dd" });
// 3. 金额列添加数据验证(0-100000)
sheet.AddRangeDataValidation(new DataValidation(
new RangePosition("C2:C100"),
DataValidationType.Decimal, 0, 100000));
// 4. 监听数据变更做实时计算
sheet.CellDataChanged += (s, e) => {
if (e.Cell.Column == 2) // C 列变更时重算合计
sheet["C101"] = "=SUM(C2:C100)";
};
// 5. 提供保存按钮
btnSave.Click += (s, e) => grid.Save("data.xlsx", FileFormat.Excel2007);
sheet["A1"] = ... 方式快速填充测试数据SetRangeData() + SuspendUIUpdates()WorksheetRangeStyle 实例,避免在循环内创建sheet["A1"] = val) 在千行以上会很慢,必须改用 SetRangeData()SuspendUIUpdates() / ResumeUIUpdates()Recalculate(),或在 CellDataChanged 事件中手动触发PerMonitorV2,否则控件模糊| 场景 | 推荐方案 |
|---|---|
| 简单数据展示/导出 | 直接用 NPOI,无需 ReoGrid |
| WinForms/WPF 内嵌可编辑表格 | ReoGrid |
| 纯 Excel 文件处理(无 UI) | NPOI |
| 复杂图表/数据透视表 | 商业控件(Spread.NET / Aspose.Cells) |
| 问题 | 解决 |
|---|---|
| V3社区版功能有限(如缺少部分高级功能),商业闭源建议购买V4商业许可 | 购买 V4 商业许可获取完整功能 |
| WPF 高 DPI 模糊 | 启用 PerMonitorV2 DPI |
| 公式不计算 | 调用 sh.Recalculate() |
| Excel 打开样式丢失 | 仅支持核心样式,复杂样式建议直接 NPOI 处理 |