ReoGrid 提供了一个称为 ICellBody 的接口,用于创建自定义单元格。单元格主体可以嵌入到单元格中,它会自动适应单元格的尺寸并获取单元格的某些资源访问权限。
当单元格主体被分配到单元格后,它会无缝集成到单元格中,自动适应单元格大小并与单元格的属性和方法交互。
这是一个在单元格内显示红色进度条的单元格主体示例。
更多示例可在演示项目中查看。
要在 ReoGrid 中创建自定义单元格主体,
我们必须用 C# 代码编写一个继承自 CellBody 的类或实现 ICellBody 接口。CellBody 类提供了多种可重写的方法,用于自定义单元格的行为和外观。
CellBody 类作为自定义单元格主体的基类,封装了单元格自定义所需的通用功能和属性。
调用 C# CellBody 或 ICellBody 前请确保导入以下命名空间:
using System;
using unvell.ReoGrid;
using unvell.ReoGrid.CellTypes;
using unvell.ReoGrid.Events;
using unvell.ReoGrid.Rendering;
using unvell.ReoGrid.Graphics;
using unvell.ReoGrid.Interaction;
这个框架通过利用 CellBody 类或 ICellBody 接口,为扩展 ReoGrid 单元格功能提供了结构化方法。
首先我们在 aardio 里调用 C# 编译一个程序集以创建自定义的 MyCellBody 类。 当然也可以在 C# 开发环境内编译。
直接运行下面的 aardio 代码将会创建程序集 ardio.ReoGrid.dll 。
import dotNet.ReoGrid.Compiler;
var compiler = dotNet.ReoGrid.Compiler();
//引用程序集
compiler.Reference("System.Drawing");
//C# 源码
compiler.Source = /***
//请确保导入以下命名空间:
using System;
using unvell.ReoGrid;
using unvell.ReoGrid.CellTypes;
using unvell.ReoGrid.Events;
using unvell.ReoGrid.Rendering;
using unvell.ReoGrid.Graphics;
using unvell.ReoGrid.Interaction;
namespace aardio.ReoGrid{
//让类继承 CellBody
class MyCellBody : CellBody {
public override void OnPaint(CellDrawingContext dc)
{
// Define the bounds for the ellipse. Here, it fills the entire cell.
Rectangle ellipseBounds = new Rectangle(0, 0, base.Bounds.Width, base.Bounds.Height);
// Draw an ellipse within the cell using the specified bounds
dc.Graphics.DrawEllipse(SolidColor.Blue, ellipseBounds);
}
}
}
***/
compiler.CompileOrFail("/aardio.ReoGrid.dll");
在上面的示例中我们实现了自定义绘图的单元格。
首先我们重写了自定义单元格主体类 MyCellBody 中的 OnPaint 方法。通过重写 OnPaint 方法,可以为单元格执行自定义绘图操作,如绘制形状、文本或图像,从而根据特定需求增强单元格的视觉表现。
在 OnPaint 方法中:
CellDrawingContext dc:CellDrawingContext 提供绘图上下文,是用于在单元格边界内绘制形状、文本和其他图形的画布( Graphics )对象base.Bounds:表示单元格的边界,由 ReoGrid 自动维护。这里用它来定义椭圆相对于单元格的大小和位置要在 ReoGrid 中将自定义单元格主体嵌入到特定单元格,可以使用以下任一方法。这两种方法功能相同,但提供了不同的语法选项:
sheet1["C3"] = MyCellBody();
这种方法利用工作表对象的索引器,允许直接将 MyCellBody(或任何继承自 CellBody 的类)的新实例分配给 C3 位置的单元格。
sheet1.Cells["C3"].Body = MyCellBody();
这种方法通过工作表的 Cells 属性访问 C3 位置的 Cell 对象,然后将单元格的 Body 属性设置为 MyCellBody 的新实例。
这两种方法都会用新的 MyCellBody 实例替换指定单元格中现有的单元格主体。确保 MyCellBody 是一个继承自 ReoGrid 的 CellBody 类的类,这样才能自定义单元格行为和外观。
在 aardio 中创建自定义单元格的完整示例代码如下:
import win.ui;
/*DSG{{*/
var winform = win.form(text="ReoGrid - 自定义单元格")
/*}}*/
import dotNet.ReoGrid;
var grid = ReoGrid.ReoGridControl(winform);
var sheet1 = grid.CurrentWorksheet;
//用 $ 操作符内存加载 DLL,发布后生成独立 EXE,不再需要 aardio.ReoGrid.dll
var dll = dotNet.loadFile($"/aardio.ReoGrid.dll");
//导入 C# 名字空间
var gridUtil = dll.import("aardio.ReoGrid");
//加载自定义单元格
sheet1["C3"] = gridUtil.MyCellBody();
winform.show();
win.loopMessage();
运行以上 aardio 示例的的显示效果如下:

将单元格实例的 Body 属性设为 null 即可移除单元格主体:
sheet1.Cells["C3"].Body = null;
要在自定义单元格主体的绘制逻辑中按照 ReoGrid 的默认行为渲染单元格背景和文本,可以调用以下方法:
dc.DrawCellBackground(); // 重绘单元格背景
dc.DrawCellText(); // 重绘单元格文本
这些方法应该从自定义 CellBody 类的 OnPaint 方法重写中调用。dc 参数指向传递给 OnPaint 方法的 CellDrawingContext 对象,它提供了单元格渲染的绘图表面和上下文。
在自定义 CellBody 类的 C# 代码中,可以这样使用这些方法:
public override void OnPaint(CellDrawingContext dc)
{
// 绘制默认单元格背景
dc.DrawCellBackground();
// 自定义绘图逻辑
// 在背景上绘制默认单元格文本
dc.DrawCellText();
// 可以继续添加其他自定义绘图逻辑
}
示例结果:
以下是在单元格内绘制对角线的 C# 代码示例:
class DiagonalLineCell : CellBody
{
public bool FromTopLeft { get; set; }
public DiagonalLineCell() { this.FromTopLeft = true; }
public override void OnPaint(unvell.ReoGrid.RGDrawingContext dc)
{
if (FromTopLeft) {
dc.Graphics.DrawLine(Pens.Black, new Point(0, 0), new Point(Bounds.Right, Bounds.Bottom));
} else {
dc.Graphics.DrawLine(Pens.Black, new Point(0, Bounds.Bottom), new Point(Bounds.Right, 0));
}
}
}
在 aardio 中将上面的两个实例添加到工作表中:
var dll = dotNet.loadFile($"/aardio.ReoGrid.dll");
var gridUtil = dll.import("aardio.ReoGrid");
sheet1["B2"] = gridUtil.DiagonalLineCell();
sheet1["D2"] = table.assign( gridUtil.DiagonalLineCell() ,{FromTopLeft=false} );
结果:
在 C# 代码中通过重写 OnStartEdit 方法并返回 false 来阻止默认编辑操作。
private class MyCellBody : CellBody
{
public override bool OnStartEdit()
{
return false;
}
}
通过重写 OnEndEdit 方法并返回数据来替换用户编辑结果。
在 C# 代码中通过重写如 OnKeyDown 和 OnMouseDown 等方法来处理键盘和鼠标事件。
public override bool OnMouseDown(CellMouseEventArgs e)
{
// translate cursor position to percent
int value = (int)Math.Round(x * 100f / (Bounds.Width));
// update cell's data, but do not set the data to cell directly, call methods of control instead
sheet.SetCellData(e.CellPosition, value);
}

可以使用公式绑定两个单元格的数据:
sheet1["C7"] = "=E7";

ReoGrid 提供了许多内置单元格类型,如按钮、复选框、下拉列表、图像等。详见内置单元格类型。