# dotNet.ReoGrid 扩展库 - 单元格编辑

单元格可以通过以下方式进入编辑模式：
- 用户双击单元格（默认行为）
- 按下 F2 键

进入编辑模式后，控件上会显示一个文本框用于接收用户输入。

编辑界面示例：![样式化电子表格](../images/55.png)

## 检查编辑状态

使用 `IsEditing` 方法可以检查单元格是否处于编辑模式。

```aardio
// 检查当前是否有单元格正在编辑
var isEditing = sheet1.IsEditing;
```

使用 `GetEditingCell` 方法可以获取当前编辑单元格的位置：

```aardio
// 获取当前编辑的单元格
var editingCell = sheet1.GetEditingCell();
```

## 编辑控制

### 启动单元格编辑

可以通过编程方式使用 `StartEdit` 方法启动特定单元格的编辑。该方法支持通过行列索引或 ReoGrid.CellPosition 对象指定单元格：

```aardio
// 通过行列索引启动编辑（注意 aardio 中行列索引从1开始）
sheet1.StartEdit(3, 4);  // 开始编辑第4列第3行的单元格

// 通过 A1 表示法启动编辑
sheet1.StartEdit(ReoGrid.CellPosition("A1"));  // 开始编辑 A1 单元格
```

注意：如果已有单元格处于编辑状态时调用新的 `StartEdit` 命令，当前编辑操作会自动结束，然后开始新的编辑会话。

### 强制结束单元格编辑

`EndEdit` 方法可以强制终止当前单元格的编辑操作。它接受一个 `ReoGridEndEditReason` 参数，用于指定编辑结束后的行为。例如，指定 `ReoGridEndEditReason.Cancel` 会放弃所有编辑修改，恢复单元格的原始内容。

```aardio
// 强制结束当前编辑并取消修改
sheet1.EndEdit(ReoGrid.ReoGridEndEditReason.Cancel);
```

`EndEdit` 方法还可以直接设置单元格的新值：

```aardio
// 结束编辑并设置新值
sheet1.EndEdit("新值");

// 结束编辑、设置新值并指定结束原因
sheet1.EndEdit("新值", ReoGrid.ReoGridEndEditReason.Normal);
```

### 只读单元格

通过设置单元格的 `Readonly` 属性可以禁用编辑和粘贴操作：

```aardio
// 设置 A1 单元格为只读
var cell = sheet1.Cells["A1"];
cell.Readonly = true;
```

## 处理单元格编辑事件

ReoGrid 提供了一系列事件来处理单元格编辑过程，不仅可以捕获输入的字符，还可以修改输入的值。

编辑流程示意图：
![150](../images/150.png)

### 编辑前事件

当用户通过 F2 键或输入字符（包括通过输入法工具输入）启动编辑时，ReoGrid 会触发 `BeforeCellEdit` 事件。通过设置事件的 `IsCancelled` 参数可以取消编辑操作。

### 阻止单元格编辑

通过处理 `BeforeCellEdit` 事件可以阻止单元格进入编辑模式：

```aardio
// 订阅 BeforeCellEdit 事件
sheet1.BeforeCellEdit = function(sender, e) {
    // 阻止编辑
    e.IsCancelled = true;
}
```

### 编辑中事件

- `CellEditTextChanging`：当单元格文本发生变化时触发，适用于验证或替换整个文本
- `CellEditCharInputted`：当每个字符输入时触发（包括输入法输入的字符）

注意：在 WPF 版本中，`CellEditCharInputted` 事件不能修改字符，如需修改文本应使用 `CellEditTextChanging` 事件。

### 编辑后事件

编辑会话在以下情况结束：
- 用户按下 Enter 键
- 输入框失去焦点

此时会触发 `AfterCellEdit` 和 `CellDataChanged` 事件。如果按下 Escape 键取消编辑，只会触发 `AfterCellEdit` 事件。

### 示例：转换输入数据

通过处理编辑事件可以实现实时验证和转换用户输入：

```aardio
// 处理文本变化事件
sheet1.CellEditTextChanging = function(sender, e) {
    // 检查输入文本
    if (e.NewText == "特定输入") {
        // 替换为预设数据
        e.NewText = "预设数据";
    }
}
```

### AfterCellEdit 与 CellDataChanged 的区别

- `AfterCellEdit`：提供最后一次取消编辑的机会，可以恢复单元格原始状态
- `CellDataChanged`：在单元格数据发生变化时触发（包括编程修改和粘贴操作）

```aardio
// 处理编辑后事件
sheet1.AfterCellEdit = function(sender, e) {
    // 可以在这里取消编辑
    if (shouldCancel) {
        e.IsCancelled = true;
    }
}

// 处理数据变化事件
sheet1.CellDataChanged = function(sender, e) {
    // 数据已发生变化
    console.log("单元格数据已更改:", e.Cell.Data);
}
```