Custom Cell
Cell Body
ReoGrid provides an interface known as ICellBody
, which facilitates the creation of customized cells. A cell body can be embedded within a cell, where it adapts to the cell's dimensions and gains access to certain resources of the cell.
Once a cell body is assigned to a cell, it seamlessly integrates with the cell, conforming to its size and interacting with the cell's properties and methods.
Sample
A sample of a cell body that displays the red progress bar inside cells.
More samples available in the demo project.
Interface of Cell Body
To create a custom cell body in ReoGrid, it must either inherit from the CellBody
class or implement the ICellBody
interface. The CellBody
class offers a variety of methods that can be overridden to customize the behavior and appearance of the cell.
Ensure the following namespaces are imported before utilizing the CellBody
or ICellBody
:
using unvell.ReoGrid.CellTypes;
using unvell.ReoGrid.Events;
using unvell.ReoGrid.Rendering;
The CellBody
class acts as a base for custom cell bodies, encapsulating common functionality and properties required for cell customization.
public class CellBody : ICellBody
{
public ReoGridCell Cell { get; set; }
// Called when the cell body is associated with a cell.
public virtual void OnSetup(ReoGridCell cell) { }
public virtual Rectangle Bounds { get; set; }
public virtual void OnBoundsChanged() { }
public bool AutoCaptureMouse() { return true; }
public virtual void OnMouseDown(CellMouseEventArgs e) { }
public virtual void OnMouseMove(CellMouseEventArgs e) { }
public virtual void OnMouseUp(CellMouseEventArgs e) { }
public virtual void OnMouseEnter(CellMouseEventArgs e) { }
public virtual void OnMouseLeave(CellMouseEventArgs e) { }
public virtual void OnMouseWheel(CellMouseEventArgs e) { }
public virtual void OnKeyDown(KeyCode e) { }
public virtual void OnKeyUp(KeyCode e) { }
public virtual void OnPaint(CellDrawingContext dc) { }
public virtual bool OnStartEdit() { return true; }
public virtual object OnEndEdit(object data) { return data; }
public bool DisableWhenCellReadonly { get { return true; } }
public virtual object OnPaste(object data) { return data; }
public virtual void OnGotFocus() { }
public virtual void OnLostFocus() { }
public virtual object OnSetData(object data) { return data; }
}
This framework provides a structured approach to extend cell functionality in ReoGrid by leveraging the CellBody
class or the ICellBody
interface.
Create a cell body
Make class inherit from CellBody
, and add its instance into a worksheet.
private class MyCellBody : CellBody
{
public MyCellBody() {
// ...
}
}
Set cell body into a cell
To embed a custom cell body into a specific cell in ReoGrid, utilize either of the following methods. Both approaches are functionally equivalent, but they offer different syntactic options based on your preference:
- Using the indexer on the sheet object:
sheet["C3"] = new MyCellBody();
This method leverages the indexer of the sheet object, allowing you to directly assign a new instance of MyCellBody
(or any other class derived from CellBody
) to the cell at position C3.
- Setting the Body property on the Cell object:
sheet.Cells["C3"].Body = new MyCellBody();
This approach accesses the Cell
object at position C3 through the Cells property of the sheet. It then sets the Body property of the cell to a new instance of MyCellBody
.
Both of these methods replace any existing cell body in the specified cell with the new MyCellBody
instance. Ensure that MyCellBody
is a class that extends ReoGrid's CellBody class, allowing you to customize cell behavior and appearance.
Remove cell body from cell
Set Body
property of cell instance to null to remove the cell body:
sheet.Cells["C3"].Body = null;
Owner Drawing
To implement custom drawing within a cell in ReoGrid, you can override the OnPaint
method in your custom cell body class. This method provides a canvas RGDrawingContext
for drawing graphics within the cell's boundaries.
Example: Drawing an Ellipse
Below is an example of a custom CellBody
class that draws an ellipse within the cell:
private class MyCellBody : CellBody
{
public override void OnPaint(RGDrawingContext 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(Pens.Blue, ellipseBounds);
}
}
In this example:
RGDrawingContext dc
: Provides the drawing context, including the Graphics object used for drawing shapes, text, and other graphics.base.Bounds
: Represents the cell's boundaries and is maintained automatically by ReoGrid. It's used here to define the size and position of the ellipse relative to the cell.
By overriding the OnPaint
method, you can perform custom drawing operations for the cell, such as drawing shapes, text, or images, thereby enhancing the cell's visual representation according to your specific requirements.
Drawing Default Cell Text and Background
To render the cell's background and text in accordance with ReoGrid's default behavior, invoke the following methods within your custom cell body's drawing logic:
dc.DrawCellBackground(); // To redraw the cell background
dc.DrawCellText(); // To redraw the cell text
These methods should be called from within the override of the OnPaint
method in your custom CellBody
class. The dc
refers to the CellDrawingContext
object passed to the OnPaint
method, which provides the drawing surface and context for cell rendering.
Example Usage: In a custom CellBody
class, you might use these methods as follows:
public override void OnPaint(CellDrawingContext dc)
{
// Draw the default cell background
dc.DrawCellBackground();
// Custom drawing logic here
// Draw the default cell text on top of the background
dc.DrawCellText();
// Additional custom drawing logic can follow
}
An sample result:
Example: draw diagonal line inside cell
Below is an example to draw diagonal lines inside cell. Make the custom cell body:
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));
}
}
}
Add two instances into worksheet:
sheet["B2"] = new DiagonalLineCell();
sheet["D2"] = new DiagonalLineCell() { FromTopLeft = false };
The result:
Disable cell edit
By overriding OnStartEdit
method and return false to prevent the default edit operation.
private class MyCellBody : CellBody
{
public override bool OnStartEdit()
{
return false;
}
}
Change edit result
By overriding OnEndEdit
method and return data to replace the user edit result.
Handle mouse and keyboard events
By overriding such as OnKeyDown
and OnMouseDown
methods to handle the keyboard and mouse events.
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);
}
Data bind by using formula
It is possible to bind two cell's data by using formula:
sheet["C7"] = "=E7";
Built-in cell types
ReoGrid provides many built-in cell types such as Button, Check box, Drop-down list, Image and etc. See Built-in Cell Types.