# dotNet.ReoGrid 扩展库 - 单元格（Cell）

单元格是工作表中的基本单元，作为各类内容和设置的主要容器。

单元格具有以下关键特性和功能：

* **合并**：单个单元格可以合并形成更大的单元格，便于分组数据展示和布局定制。
* **数据存储**：单元格能够存储多种数据类型，从简单的文本、数字到更复杂的数据结构。
* **[样式设置](./cell/style.html)**：单元格可以单独设置样式，支持自定义字体、颜色、边框等，增强视觉区分和可读性。
* **[数据格式化](./cell/data-format.html)**：通过数据格式化设置控制单元格数据的显示方式，例如货币、日期、百分比等格式。
* **[自定义内容](./cell/custom-cell.html)**：单元格可以承载自定义内容，支持下拉列表、按钮等交互元素。

这种多功能性使单元格成为工作表的核心构建块，支持从简单数据表到复杂交互仪表盘的各种应用场景。

## 定位工作表中的单元格

在 ReoGrid 中，可以通过以下三种常用方法定位工作表中的单元格，每种方法适用于不同场景：

* **地址字符串**：使用传统的电子表格单元格地址格式，结合列字母和行号。例如 "D5" 表示第 D 列第 5 行的单元格。
* **行列数字索引**：直接指定行和列的数值索引（从 0 开始）。例如 (4, 3) 表示第 5 行第 4 列的单元格。
* **ReoGrid.CellPosition 结构体**：使用 ReoGrid.CellPosition 结构体封装单元格位置，提供类型安全的方法来引用单元格位置。

这些多样化的方法为单元格引用提供了灵活性，适应从简单单元格访问到复杂程序交互的各种使用场景。

### ReoGrid.CellPosition 结构体

创建 `ReoGrid.CellPosition` 实例来定位单元格：

```aardio
// 通过地址字符串定位单元格
var pos = ReoGrid.CellPosition("D5");  // 定位地址 D5

// 通过数字索引定位单元格（行和列索引从0开始）
var pos = ReoGrid.CellPosition(4, 3);  // 行:4, 列:3
```

创建 `ReoGrid.CellPosition` 实例后，可以使用 `ToAddress` 方法将其转换为地址字符串：

```aardio
var address = pos.ToAddress();  // 结果为 D5
```

以下静态方法用于检查地址是否有效：

```aardio
ReoGrid.CellPosition.IsValidAddress("D5");       // true
ReoGrid.CellPosition.IsValidAddress("A1:D5");    // false
ReoGrid.CellPosition.IsValidAddress("myrange");  // false，但 sheet1["myrange"] 是有效的
```

## 单元格数据

单元格数据是工作表中显示的值，也用于公式计算。

### 设置单个单元格数据

通过单元格地址写入单元格：

```aardio
sheet1["A1"] = 10;
```

通过行列数字索引（.NET 多维索引从 0 开始）写入单元格：

```aardio
sheet1[0, 0] = 10;          // A1: 数字
sheet1[0, 1] = "string";     // B1: 字符串
sheet1[0, 2] = time.now();   // C1: 日期时间
```

通过 ReoGrid.CellPosition 结构体写入单元格。

```aardio
sheet1[ReoGrid.CellPosition("A1")] = 10;
sheet1[pos] = "string";
```

通过命名范围设置：

```aardio
// 定义命名范围
sheet1.DefineNamedRange("mycell", ReoGrid.RangePosition("A1"));
// 设置数据
sheet1["mycell"] = 10.12345;
```

了解更多关于[命名范围](./worksheet/named-range.html)的信息。

设置自定义数据类型：

```aardio
// 自定义数据类
class MyData {
    ctor(){
        this.ToString = function(){
            return "mydata";
        }
    }
}
sheet1["D1"] = MyData();
```

通过方法调用设置数据：

```aardio
sheet1.SetCellData(5, 2, "hello world");
sheet1.SetCellData(ReoGrid.CellPosition(5, 2), "hello world");
```

### 设置范围数据

将数组数据设置到范围中：

```aardio
sheet1["A1:C1"] = ["A", "B", "C", "D"];  // 数据仅在范围内填充
sheet1["A2"] = ["D", "E", "F"];          // 无边界限制，填充所有数据
sheet1["A3:A5"] = [10, 11, 12];          // 垂直填充
sheet1[1,1] = [ ['a', 'b', 'c'], [1, 2, 3], [4, 5, 6] ];
sheet1.SetRangeData(ReoGrid.RangePosition(1, 1, 3, 3), [ ['a', 'b', 'c'], [1, 2, 3], [4, 5, 6] ]);
```

#### 设置数据和撤销

使用 `DoAction` 和传递 `SetCellDataAction` 实例设置数据可以提供撤销操作的能力：

```aardio
grid.DoAction(SetCellDataAction("B5", "hello world"));
// 撤销更改
grid.Undo();
// 重做更改
grid.Redo();
```

### ReoGrid 中的单元格数据类型处理

ReoGrid 智能评估输入单元格的数据，并自动选择适当的数据类型来应用格式化和显示格式化内容。单元格数据处理方式如下：

* **空数据**：当单元格数据设置为 null 时，单元格将保持为空，不显示任何内容。
* **对象数据**：如果分配给单元格的数据是对象类型（包括用户定义的自定义对象），ReoGrid 会调用对象的 `ToString` 方法获取字符串表示形式用于显示。此外，原始对象会被保留并用于涉及该单元格的任何公式计算。

这种动态数据类型确定和格式化机制使 ReoGrid 能够无缝处理各种类型的单元格内容，通过提供上下文适当的数据呈现和功能来增强用户体验。

## 单元格实例

在首次创建 ReoGrid 组件时，并不会立即为每个可能的单元格位置生成单元格实例。相反，ReoGrid 采用更高效的方法，按需创建单元格实例。这意味着特定单元格实例仅在必要时（例如向该单元格分配数据或样式时）才会被实例化。

考虑这样一种情况：向单元格 A1 应用了数据或样式，但没有对 B1 进行任何设置。在这种情况下，ReoGrid 将为 A1 创建一个实例来存储其数据和样式信息。相反，由于没有为 B1 设置任何信息，它仍然没有实例化的单元格对象。

这种方法有助于通过避免实例化单元格对象直到真正需要它们来节省资源，从而提高 ReoGrid 组件的整体效率和性能。

## 获取单元格实例

要获取单元格实例，请使用以下单元格集合：

```aardio
var cell = sheet1.Cells["A1"];      // 通过地址获取单元格
var cell = sheet1.Cells[1, 2];     // 通过行列索引获取单元格
var cell = sheet1.Cells["C2"];     // 通过地址获取单元格
var cell = sheet1.Cells["myname"]; // 获取命名范围内的第一个单元格
```

单元格集合在返回之前总是会创建单元格实例，不要使用此集合迭代所有单元格，因为它会创建大量空实例占用内存，而应使用以下方法：

```aardio
var cell = sheet1.GetCell("A1");
```

请注意，单元格实例可以为 null，当单元格未设置任何数据或资源时：

```aardio
if (cell != null) {
    // 处理单元格
}
```

还有另一种方法可以获取非 null 的单元格实例，`CreateAndGetCell` 方法会在实例不存在时创建一个新单元格实例再返回（此方法与单元格集合的效果相同）：

```aardio
var cell = sheet1.CreateAndGetCell(2, 3);
```

## 自动数据格式化

ReoGrid 采用自动数据格式系统，在首次向单元格输入数据时激活。该系统分析输入并自动分配适当的数据类型，应用相应的格式化规则。例如：

* **数值数据**：如果输入被识别为数字，ReoGrid 会应用默认的数字格式，确保数值数据显示一致。
* **文本对齐**：对于某些数据类型（如数字、日期和百分比），ReoGrid 会自动将文本对齐方式调整为右对齐，增强可读性并保持类似数据类型的标准呈现样式。

### 禁用自动数据格式化

虽然自动数据格式化在许多场景中很有用，但在某些情况下可能需要手动控制单元格格式化。要关闭此自动功能，可以修改[工作表设置](./worksheet/settings.html)中的 `Edit_AutoFormatCell` 设置：

```aardio
// 为工作表禁用自动数据格式化
sheet1.SetSettings(ReoGrid.WorksheetSettings.Edit_AutoFormatCell, false);
```

更多关于[数据格式](./cell/data-format.html)和[工作表设置](./worksheet/settings.html)的信息。

### 自动数据类型转换

ReoGrid 会将数据类型更改为其他类型以加快公式计算速度。例如，当字符串数据 "10" 被设置到指定了数字格式的单元格时，该字符串将自动转换为数字（在 .NET 中为 double）。要防止此转换并保留原始字符串 "10" 在单元格中，请将单元格的数据格式更改为"文本"。参见[数据格式](./cell/data-format.html)。

ReoGrid 智能管理数据类型以优化性能，特别是在公式计算期间。当数据输入到单元格时，ReoGrid 会评估上下文和单元格的指定格式，以确定是否需要进行数据类型转换以提高效率。例如：

* **字符串到数字的转换**：如果表示数字值的字符串（如 "10"）被输入到格式化为数字的单元格中，ReoGrid 会自动将该字符串转换为数字数据类型（通常在 .NET 中为 double）以方便快速计算。

### 保留原始数据类型

要保留原始数据类型并防止自动转换，可以明确将单元格的数据格式设置为"文本"。这种方法确保输入（如字符串 "10"）保留其字符串数据类型，而不会自动转换为数字类型。

示例：演示自动数据类型转换

考虑以下代码片段，它说明了 ReoGrid 如何处理数据类型转换：

```aardio
// 默认情况下，字符串 "10" 会自动转换为数字值
sheet1[3, 1] = "10";  // 字符串 "10" 自动转换为数字 10
assert(sheet1.GetCellData(3, 1) == 10);

// 将单元格的数据格式设置为"文本"以保留原始字符串数据类型
sheet1.SetRangeDataFormat(3, 2, 1, 1, DataFormat.CellDataFormatFlag.Text, null);
sheet1[3, 2] = "10";  // 字符串 "10" 保留为字符串，不进行自动转换

// 尽管存储为字符串，数据在需要时仍可解释为数字值
assert(sheet1.GetCellData(3, 2) == "10");  // 验证数据存储为字符串
assert(sheet1.GetCellData(3, 2) == 10);    // 演示字符串 "10" 可解释为整数
assert(sheet1.GetCellData(3, 2) == 10.0);  // 演示字符串 "10" 可解释为双精度浮点数
```

## 管理单元格中的文本溢出

与 Excel 类似，ReoGrid 设计为允许单元格的文本内容在超出单元格宽度时溢出到相邻单元格中。这种默认行为确保长文本保持可见，前提是相邻单元格不包含任何文本。

### 禁用文本溢出

如果不需要文本溢出行为，可以通过工作表设置轻松禁用它：

```aardio
// 在工作表中禁用单元格文本溢出
sheet1.DisableSettings(ReoGrid.WorksheetSettings.View_AllowCellTextOverflow);
```

此调整可防止文本溢出到相邻单元格，确保文本内容限制在其原始单元格的边界内。此功能允许更好地控制 ReoGrid 工作表中单元格数据的呈现和可读性。