SourceGrid应用中文帮助

SourceGrid应用中文帮助
SourceGrid应用中文帮助

1.简介

SourceGrid 是一个完全以C# 托管代码编写的.NET Windows 窗体网格控件. SourceGrid 可用于显示或改变表格形式的数据。

SourceGrid 可用于绑定到一个数据源(以DataView 为代表),或者直接建立每个单元格。

SourceGrid 仅使用托管代码(无API 或Interop),可以用于任何与.NET 2 兼容的环境中。

2.安装

要使用SourceGrid,你必须有与.NET 2 兼容的开发环境(如Visual Studio 2005)。要下载控件的最新版,请访问https://www.360docs.net/doc/9e14186448.html,/projects/sourcegrid. 解压缩该文件后,可参考项目中的这些程序集:

SourceGrid.dll - SourceGrid 内核库

DevAge.Core.dll - 共用的辅助功能库

DevAge.Windows.Forms.dll - Windows 窗体库

[SourceGrid.Extensions.dll - 可选库,有SourceGrid 扩展功能(如DataGrid, PlanningGrid)]

典型地,我总是建议把它们复制到与*.xml文件相同的位置,你可以在程序集相同的目录中找到,以便使用IDE的智能感应录入功能。

打开你想要添加网格控件的表单,打开IDE的工具箱,工具箱->右键->选择项->浏览并增加SourceGrid.dll 和SourceGrid.Extensions.dll 程序集到IDE的工具箱中。这些程序集是运行时刻所需的,需要随同你的应用程序一起分发给最终用户。

3.SourceGrid 控件

有2 种主要的控件包含在SourceGrid.dll 程序集中:

GridVirtual 控件- 使用虚单元格(ICellVirtual)的网格控件

Grid 控件- 使用实体单元格(ICell)的网格控件

因此有 2 种不同的基础对象:虚单元格和实体单元格。虚单元格是确定外观和行为,但不包含值的单元格。实体单元格与虚单元格有相同的属性,但也包含单元格的值,因此在网格中与特定位置相关联。

在不需要显示大量单元格(典型地,应少于50,000 个单元格)时,可以使用任何类型的Grid 控件。如果需要显示大量单元格,通常你必须使用一个派生于GridVirtual 的控件。

典型地,在本文中,我将使用Grid 控件,因为它更简单,尤其是作为简单的示例。但是,同样的代码基本上也能用于GridVirtual 控件。

Grid 控件也用作需要最大弹性的那些特殊的网格。

拖动Grid 控件到你的窗体中,就如同添加其它任何.NET 控件一样,然后开始使用它。

4.基础示例

目前,SourceGrid 仅有少量的设计时刻支持,因此通常你必须人工编写代码操作网格。

假定你已经有一个名为grid1 的Grid 控件,你可以在Form.Load 事件中编写如下代码:

grid1.BorderStyle = BorderStyle.FixedSingle;

grid1.ColumnsCount = 3;

grid1.FixedRows = 1;

grid1.Rows.Insert(0);

grid1[0,0] = new SourceGrid.Cells.ColumnHeader("String");

grid1[0,1] = new SourceGrid.Cells.ColumnHeader("DateTime");

grid1[0,2] = new SourceGrid.Cells.ColumnHeader("CheckBox");

for (int r = 1; r < 10; r++)

{

grid1.Rows.Insert(r);

grid1[r,0] = new SourceGrid.Cells.Cell("Hello " + r.ToString(), typeof(string));

grid1[r,1] = new SourceGrid.Cells.Cell(DateTime.Today, typeof(DateTime));

grid1[r,2] = new SourceGrid.Cells.CheckBox(null, true);

}

grid1.AutoSizeCells();

可以看到,你能像使用 2 维数组一样来使用grid。在上面的代码中,我已经设置了网格的边框,列数,固定行数,建立了一个标头行。对此标头,我使用了一种ColumnHeader 单元格。我已经为每列使用了特定类型,从而以一种简单的外观建立了其他单元格。Cell 类自动为指定类型建立了一个适当的编辑器(在本例中为一个文本框和一个日期时间选择器)。对最后一列,我使用了一个复选框单元格(CheckBox cell),允许在单元格中直接显示复选框。每种单元格定义了它自己的可视外观和行为。

建立的网格支持排序,可改变列宽和编辑单元格。

下面是一些重要的功能:

如果你想读取或改变单元格中的值,可以使用grid1[r,c].V alue 属性,r 和 c 是单元格的行和列。

删除某行,可以编写代码如:grid1.Rows.Remove(r)

改变列宽,可以编写代码如:grid1.Columns[c].Width = 100

如果你想改变某些单元格的可视属性,你必须使用View 类。

让我们看看下一个示例:

grid1.BorderStyle = BorderStyle.FixedSingle;

grid1.ColumnsCount = 3;

grid1.FixedRows = 1;

grid1.Rows.Insert(0);

SourceGrid.Cells.Views.ColumnHeader boldHeader =

new SourceGrid.Cells.Views.ColumnHeader();

boldHeader.Font = new Font(grid1.Font, FontStyle.Bold | FontStyle.Underline); SourceGrid.Cells.Views.Cell yellowView = new SourceGrid.Cells.Views.Cell(); yellowView.BackColor = Color.Y ellow;

SourceGrid.Cells.Views.CheckBox yellow ViewCheck =

new SourceGrid.Cells.Views.CheckBox();

yellowViewCheck.BackColor = Color.Y ellow;

grid1[0, 0] = new SourceGrid.Cells.ColumnHeader("String");

grid1[0, 0].View = boldHeader;

grid1[0, 1] = new SourceGrid.Cells.ColumnHeader("DateTime");

grid1[0, 1].View = boldHeader;

grid1[0, 2] = new SourceGrid.Cells.ColumnHeader("CheckBox");

grid1[0, 2].View = boldHeader;

for (int r = 1; r < 10; r++)

{

grid1.Rows.Insert(r);

grid1[r, 0] = new SourceGrid.Cells.Cell("Hello " + r.ToString(), typeof(string));

grid1[r, 0].View = yellowView;

grid1[r, 1] = new SourceGrid.Cells.Cell(DateTime.Today, typeof(DateTime));

grid1[r, 1].View = yellowView;

grid1[r, 2] = new SourceGrid.Cells.CheckBox(null, true);

grid1[r, 2].View = yellowViewCheck;

}

我使用FontStyle.Bold | FontStyle.Underline 建立了一个列标头外观,其中标准单元格的外观为黄色背景,复选框单元格的外观为黄色背景。然后我把它们的实例指派到了每个单元格的View 属性中。

窗体看起来应该像下图所示的一样:

你可以注意到,我已经为许多单元格指派了View 类的同一个实例。这对于优化所耗用的系统资源是有用的。

每个单元格可以有一个编辑器(Editor 属性) 相关。编辑器用于编辑单元格的值。你可以人工建立一个编辑类(参阅SourceGrid.Cells.Editors 命名空间),或者使用SourceGrid.Cells.Editors.Factory 类建立基于某种类型(Type)的编辑器。如果指定了Type 参数,你也可以使用Cell 构造函数自动调用

SourceGrid.Cells.Editors.Factory 。

下面是一个示例,建立一些单元格,并且使用上面所述的某一种方法把单元格与

编辑器相关联。

//A DateTime editor

grid1[r, c] = new SourceGrid.Cells.Cell(DateTime.Today, typeof(DateTime));

//A string editor

grid1[r, c] = new SourceGrid.Cells.Cell("Ciao", typeof(string));

//A double editor

grid1[r, c] = new SourceGrid.Cells.Cell(58.4);

grid1[r, c].Editor = SourceGrid.Cells.Editors.Factory.Create(typeof(double));就像View 类一样,编辑器也可以在一个或数个单元格之间被共用。

现在,你可以开始使用SourceGrid 工作了。

5.基础概念

5.1Grid 控件

如果你需要最有弹性的, 简易而没有太多单元格的网格, Grid 控件是理想的选择. 事实上, 此控件中每个单元格都作为一个.NET 类来描述, 因此也占用一定数量的资源. 此外, 这是唯一支持RowSpan 和ColumnSpan(单元格合并)功能的网格.

在一个Windows 窗体中Grid 控件是最普通不过的事. 这正如增加其他控件(如按钮, DataGrid)一样. 首先,建立或者打开一个Windows 应用程序项目, 然后从设计器打开一个Windows 窗体。现在你要准备好使定制工具箱: 以鼠标右键单击“工具箱—.NET Framework 组件—浏览”,选中“DevAge.SourceGrid.dll”。现在,网格控件被添加到工具箱中,可以像其他控件一样增加到Windows 窗体中。

在增加控件到窗体后,我们就可以开始编写代码使用网格控件. 例如,在窗体的Load 事件中,编写如下代码:

grid1.Redim(2, 2);

grid1[0,0] = new SourceGrid.Cells.Cell("Hello from Cell 0,0");

grid1[1,0] = new SourceGrid.Cells.Cell("Hello from Cell 1,0");

grid1[0,1] = new SourceGrid.Cells.Cell("Hello from Cell 0,1");

grid1[1,1] = new SourceGrid.Cells.Cell("Hello from Cell 1,1");

上述代码建立一个2 行 2 列(Redim 方法) 的表,以单元格装入各个位置。我已经使用了包含实体单元格的SourceGrid.Cells 命令空间。

可以使用V alue 属性读取特定单元格的值,就像这样:object val = grid1[1,0].V alue;.

5.2GridVirtual 控件

当需要显示大量的单元格, 并且已经有可用的结构化数据(例如数据集, 数组, XML文档或其他数据结构)时, 使用GridVirtual 控件是理想的选择.

除了自动排序(这是因为在复制任何外部数据结构的内容之前, grid 不能进行自动排列), 以及RowSpan 和ColumnSpan 这类允许单元格交叉跨越其它邻近单元格的功能(例如合并单元格功能)以外, 这种GridVirtual 网格控件与Grid 控件有同样的功能.

另一个缺点是建立虚网格稍显困难.

虚网格主要的概念是, 每个单元格从一个外部的数据结构读取和写入值, 以及网格不持有所有行和列, 而通常是直接从数据源中读取.

此观点以一个抽象的GridVirtual 类实现, 并且有抽象的方法: CreateRowsObject, CreateColumnsObject 和GetCell. 你可以使用特定的IV alueModel (接口)直接从数据源中读取值.

因此对于GridVirtual , 需要建立一个派生于GridVirtual 的类, 并且定制CreateRowsObject, CreateColumnsObject 和GetCell 方法读取数据源是首要的. GetCell 方法的主要目的是返回一个给定的位置(行或列), 选定的单元格, 以及用于建立列和行对象CreateRowsObject 和CreateColumnsObject 方法使用的数据源。这样允许很大的弹性, 因为你可以返回任何ICellVirtual 给一个特定的类型; 举例来说, 当行号为0 时, 你可以返回单元格的标头类型.

通常, 你不需要直接使用GridVirtual , 而是需要使用一个从它派生的控件.

目前, 我已经完成两个可以直接使用虚网格功能的控件:

DataGrid - 绑定到DataView 对象的网格.

ArrayGrid - 绑定到一个Array 对象的网格

如果你需要建立自定义控件, 从特定数据源读取数据, 你可以参阅ArrayGrid 类的示例.

6.单元格概述

每个单元格由 4 个基本部分组成, 它们基于改进的“模式-外观-控制器(Model-View-Controller)”模型:

模式(Model): 模式是管理单元格取值的类, 它包含相关的取值或属性, 并且与其他组件相联系.

外观(View) : 外观是绘制单元格, 并包含可视属性的类.

控制器(Controller) : 控制器是提供单元格行为的类.

编辑器(Editor) : 编辑器是定制单元格的编辑器的类.

这种划分为代码提供了很大的弹性和可重用性, 可节约时间, 为每种定制类型提供可靠的基础。

为了较通用的要求,一些类已经被准备和配置, 但是, 可能会需要以某些代码行建立个性化单元格。

6.1行和列

网格主要的组成是行和列. 为处理这些信息, SourceGrid 应用 2 个属性:

Rows - 管理行信息, 基础类是RowsBase 类.

Columns - 管理行信息, 基础类是ColumnsBase 类.

当使用一个实体网格时, 基础类被以RowInfoCollection 和ColumnInfoCollection 扩展, 它们是RowInfo 类和ColumnInfo 类的集合. 当使用一个虚网格时, 你必须以自己的代码提供数据源的信息, 从而扩展基础类.

在实体网格上操作行和列

注意: 仅对实体网格有效.

这是RowInfo 类的一部分属性: Height, Top, Bottom, Index, Tag. 与之相反, ColumnInfo 类的一部分属性为:Width, Left, Right, Index, Tag.

有多种方式建立行和列:

示例1:grid1.Redim(2,2);

示例2:grid1.RowsCount = 2;

grid1.ColumnsCount = 2;

示例3:grid1.Rows.Insert(0);

grid1.Rows.Insert(1);

grid1.Columns.Insert(0);

grid1.Columns.Insert(1);

上面这三个示例完成同样的任务: 建立一个2 行 2 列的表.

可以使用下列代码改变行或列的宽度或高度:

grid1.Rows[0].Height = 100;

grid1.Columns[0].Width = 100;

使用行或列的宽度及高度时, 属性Top, Bottom, Left 和Right 被自动计算.

在分配行和列后, 你必须为网格建立所需单元格的各个位置, 就像这些代码一样:

grid1.Redim(2,2);

grid1[0, 0] = new SourceGrid.Cells.Cell("Cell 0, 0");

grid1[1, 0] = new SourceGrid.Cells.Cell("Cell 1, 0");

grid1[0, 1] = new SourceGrid.Cells.Cell("Cell 0, 1");

grid1[1, 1] = new SourceGrid.Cells.Cell("Cell 1, 1");

7.模式(Model)

命名空间: SourceGrid.Cells.Models

模式类(Model classes)的目的是把单元格对象和单元格数据分离出来, 这有两个主要的原因:

在值只需要被存储在原始数据源的情况下, 执行虚网格。在此情况下, 如果以正确的方式选择模式, 可以从数据源直接地读取数据。

需要扩充单元格类, 但是维持代码的易于重用性。这是因为你不一定要改变基

本的单元格类(Cell class)来增加新的功能,而是可以只增加一个新的模式。

每个单元格都有Model 属性, 用于返回或设置一个ModelContainer 对象. 此类是IModel 接口的一个集合. 每个IModel 接口包含所有用于特定功能的属性.

主要的模式(Model) 是值模式(V alueModel), 包含单元格的值, 但也有其他模式供你建立定制的模式. 下面是默认的模式:

IV alueModel

IToolTipText

ICheckBox

ISortableHeader

每种模式包含各自特定功能的属性, 例如IToolTipText 包含提示条字符串.

每个单元格都有一个模式的集合, 允许使用单个单元格上的众多功能.

通常, 使用实体单元格时, 你可以使用一种模式简单实现以适当的接口直接存储所需的数据; 使用虚网格时, 你可以实现直接从外部数据源绑定值的接口. 8.外观(View)

命名空间: SourceGrid.Cells.Views

每个单元格都有一个View 属性, 返回或设置一个IView 类型的接口. 单元格使用此接口绘制和定制单元格的可视属性.

外观(View)的目的是从代码的其余部分中把绘图代码分离出来, 并且允许在单元格之间共用相同的可视特性。事实上,外观的同一实例可同时用于多个单元格, 这样, 可实现对系统资源使用的优化.

在SourceGrid.Cells.Views 命名空间中, 默认的外观类(View classes) 如下: SourceGrid.Cells.Views.Cell - 用于标准的单元格, 在此种外观下, 可以定制颜色, 字体, 边框和许多属性.

SourceGrid.Cells.Views.Button - 用于按钮风格的单元格, 有主题(theme)支持. SourceGrid.Cells.Views.Link - 用于链接风格的单元格.

SourceGrid.Cells.Views.CheckBox* - 用于复选框类型的单元格. 复选框可被选中, 禁止和包含标题文本.

SourceGrid.Cells.Views.Header* - 用于一般的标头单元格.

SourceGrid.Cells.Views.ColumnHeader* - 用于列标头单元格, 有主题(theme)支持.

SourceGrid.Cells.Views.RowHeader - 用于行标头单元格, 有主题(theme)支持SourceGrid.Cells.Views.MultiImages - 允许在单元格中绘制多个图像.

*星号标识的外观需要特定的组件恰当工作, 例如复选框外观(CheckBox view)需要一个ICheckBoxModel.

上面的某些类包含一个或数个有便捷默认实例的静态属性.

下面的代码演示如何建立一个外观类(View class), 改变单元格的某些属性, 并把它指派到上面建立的单元格中:

SourceGrid.Cells.Views.Cell view = new SourceGrid.Cells.Views.Cell();

view.BackColor = Color.Khaki;

grid1[0,0].View = view;

grid1[2,0].View = view;

编写一些代码行,你可以建立定制的外观,在此情况下,建议从已经拥有某些默认方法的Cell 派生类。在下面的示例中,建立这样一个外观——在单元格上绘制一个红色椭圆:

public class MyView : SourceGrid.Cells.Views.Cell

{

protected override void DrawCell_Background(SourceGrid.Cells.ICellVirtual p_Cell, SourceGrid.Position p_CellPosition, PaintEventArgs e, Rectangle p_ClientRectangle)

{

base.DrawCell_Background (p_Cell, p_CellPosition, e, p_ClientRectangle);

e.Graphics.DrawEllipse(Pens.Red, p_ClientRectangle);

}

}

以下列代码使用新的外观(View):

MyView myView = new MyView();

//填充网格代码

grid1[r, c].View = myView;

9.使用控制器(Controller)

命名空间: SourceGrid.Cells.Controllers

每个单元格都有一个Controller 属性,返回或设置为一个ControllerContainer 对象. 该类是一个IController 接口的集合。通过使用多个事件(如Click, MouseDown, KeyPress, ...), 每个IController 接口都可以被用于扩展单元格行为. 下面是默认的类:

SourceGrid.Cells.Controllers.Cell - 单元格的共有行为.

SourceGrid.Cells.Controllers.Button - 单元格作为按钮.

SourceGrid.Cells.Controllers.CheckBox* - 单元格有复选框行为(需要ICheckBox 模式)

SourceGrid.Cells.Controllers.ColumnFocus - 当单击标头单元格时, 用于设置列的焦点.

SourceGrid.Cells.Controllers.ColumnSelector - 当单击标头单元格时, 用于选中列. SourceGrid.Cells.Controllers.CustomEvents - 用于触发一系列事件, 而无须建立新的控制器

SourceGrid.Cells.Controllers.FullColumnSelection - 用于允许列选区模式. SourceGrid.Cells.Controllers.FullRowSelection - 用于允许行选区模式. SourceGrid.Cells.Controllers.MouseCursor - 用于显示在单元格上的鼠标指针. SourceGrid.Cells.Controllers.MouseInvalidate - 当接收到一个鼠标事件时, 用于使用单元格区失效.

SourceGrid.Cells.Controllers.Resizable - 用于建立可调整大小(宽度和高度)的单元

SourceGrid.Cells.Controllers.RowFocus - 当单击标头单元格时, 用于设置行的焦点.

SourceGrid.Cells.Controllers.RowSelector - 当单击标头单元格时, 用于选中行. SourceGrid.Cells.Controllers.SortableHeader* - 用于建立可排序的列标头单元格(需要ISortableHeader 模式)

SourceGrid.Cells.Controllers.ToolTipText* - 用于建立带提示条的单元格(需要IToolTipText 模式)

SourceGrid.Cells.Controllers.Unselectable - 用于建立不可选的单元格.

*星号标识的控制器(Controller), 需要特定的模式执行其任务.

上面的某些类包含一个或数个有便捷默认实例的静态属性.

下面是可用于控制器内部的事件:

鼠标事件: OnMouseDown, OnMouseUp, OnMouseMove, OnMouseEnter, OnMouseLeave

键盘事件: OnKeyUp, OnKeyDown, OnKeyPress

点击事件: OnDoubleClick, OnClick

焦点事件: OnFocusLeaving, OnFocusLeft, OnFocusEntering, OnFocusEntered, CanReceiveFocus

单元格取值事件: OnV alueChanging, OnV alueChanged

编辑事件: OnEditStarting, OnEditStarted, OnEditEnded

编写一些代码行,你可以建立定制的控制器(custom Controller),在此情况下,建议类从已经拥有某些默认方法的ControllerBase 派生。

在下列示例中,当用户在单元格之上移动鼠标时,建立一个改变单元格背景色的一个控制器:

public class MyController : SourceGrid.Cells.Controllers.ControllerBase

{

private SourceGrid.Cells.Views.Cell MouseEnterView = new SourceGrid.Cells.Views.Cell();

private SourceGrid.Cells.Views.Cell MouseLeaveView = new SourceGrid.Cells.Views.Cell();

public MyController()

{

MouseEnterView.BackColor = Color.Green;

}

public override void OnMouseEnter(SourceGrid.CellContext sender, EventArgs e)

{

base.OnMouseEnter (sender, e);

sender.Cell.View = MouseEnterView;

sender.Grid.InvalidateCell(sender.Position);

}

public override void OnMouseLeave(SourceGrid.CellContext sender, EventArgs e)

base.OnMouseLeave (sender, e);

sender.Cell.View = MouseLeaveView;

sender.Grid.InvalidateCell(sender.Position);

}

}

使用下面的代码, 在单元格格中使用新的控制器(Controller):

MyController myController = new MyController();

//...... code to populate the grid

grid1[r, c].AddController(myController);

你也可以添加一个控制器到整个网格中, 实现把同一控制器应用到所有的单元格中:

grid1.Controller.AddController(new MyController());

考虑下面的示例: 每次当用户单击单元格时, 下面的控制器就打开一个对话框(显示单元格取值):

class ClickController : SourceGrid.Cells.Controllers.ControllerBase

{

public override void OnClick(SourceGrid.CellContext sender, EventArgs e)

{

base.OnClick(sender, e);

object val = sender.Value;

if (val != null)

MessageBox.Show(sender.Grid, val.ToString());

}

}

你可以用下代码, 将此控制器添加到所有的单元格:

grid1.Controller.AddController(new ClickController());

下面是另一个实例, 演示当单元格改变时, 如何使用一个控制器检查, 它使用OnV alueChanged 事件:

public class V alueChangedEvent : SourceGrid.Cells.Controllers.ControllerBase

{

public override void OnValueChanged(SourceGrid.CellContext sender, EventArgs e)

{

base.OnV alueChanged(sender, e);

string val = "Value of cell {0} is '{1}'";

MessageBox.Show(sender.Grid, string.Format(val, sender.Position, sender.V alue));

}

}

你可以用下列代码, 将此控制器添加到所有的单元格:

grid1.Controller.AddController(new V alueChangedEvent());

这样, 每次当单元格的值改变时, 上面的控制器就使用单元格的位置和新的取值, 显示出一个信息对话框.

10.使用编辑器(Editor)

命名空间: SourceGrid.Cells.Editors

每个单元格都有属性Editor ,用于返回或设置一个EditorBase 对象。该类用于提供单元格编辑器。如果该属性为null,则不允许编辑单元格。

通常编辑器(Editor)使用Model 类来管理必要的转换, 特别是字符串转换(用于描述单元格取值).

下面是默认的类:

ComboBox - 组合框编辑器.

DateTimePicker - 日期时间选择编辑器

NumericUpDown - NumericUpDown 编辑.

TextBox - 文本框编辑. 这是比较常用的编辑器, 可被所有支持字符串转换的类型调用(string, int, double, enum,....).

TextBoxCurrency - 数值货币专用的文本框编辑器

TextBoxNumeric - 数值数据专用的文本框编辑器.

TimePicker - 时间值专用的DateTimePicker 编辑器.

TextBoxUITypeEditor - 提供给拥有UITypeEditor 的全部类型单元格使用. 这是一个非常有用的类, 因为许多类型都支持该类: DateTime, Font, enums, 也可以建立自定义的UITypeEditor.

ImagePicker - 一个可用于选择图像文件并且编辑byte[] 值的编辑器

在同一网格的多个单元格之间, 一个编辑器(Editor)可被共用; 举例来说,对一列中的每个单元格, 你可以使用同一个编辑器, 但是需要在同一网格中。

每个编辑器类(Editor class)都有一个Control 属性, 返回用于编辑单元格的Windows 窗体控件的一个实例. 你可以使用此实例来定制编辑器控件或实现高级功能.

下面是建立一个可被编辑的单元格的方式:

建立指定值类型的单元格. 这样, 单元格自动调用功能函数

SourceGrid.Cells.Editor.Factory.Create, 为指定类型或null 返回一个有效的编辑器(Editor).

//String cell

grid1[0, 0] = new SourceGrid.Cells.Cell("Hello", typeof(string));

//Double cell

grid1[0, 1] = new SourceGrid.Cells.Cell(0.7, typeof(double));分别建立编辑器(Editor), 然后把它指派到单元格:

//String editor

SourceGrid.Cells.Editors.IEditor editorString = SourceGrid.Cells.Editor.Factory.Create(typeof(string));

//Double editor

SourceGrid.Cells.Editors.IEditor editorDouble = SourceGrid.Cells.Editor.Factory.Create(typeof(double));

//String cell

grid1[0, 0] = new SourceGrid.Cells.Cell("Hello");

grid1[0, 0].Editor = editorString;

//Double cell

grid1[0, 1] = new SourceGrid.Cells.Cell(0.7);

grid1[0, 1].Editor = editorDouble;

当你需要为多个单元格使用相同的编辑器时, 推荐使用此方法。

人工建立适当的编辑器, 然后把它指派到单元格:

SourceGrid.Cells.Editors.TextBox txtBox =

new SourceGrid.Cells.Editors.TextBox(typeof(string));

grid1[2,0].Editor = txtBox;

如果你需要更强大的编辑器控件,或者有特别的需求时, 我建议人工建立编辑器. 举例来说明在此种情况下,人工建立类EditorTextBox , 然后设置属性MaxLength.

//String 型编辑器

SourceGrid.Cells.Editors.TextBox editorString = new SourceGrid.Cells.Editors.TextBox(typeof(string));

editorString.Control.MaxLength = 10;

//字符串单元格

grid1[0, 0] = new SourceGrid.Cells.Cell("Hello");

grid1[0, 0].Editor = editorString;编辑器也可以被用作定制单元格的格式, 在下面的代码中举例来说明(使用一种定制的数值格式):

//Double 型编辑器

SourceGrid.Cells.Editors.TextBoxNumeric editorDouble = new SourceGrid.Cells.Editors.TextBoxNumeric(typeof(double));

editorDouble.TypeConverter = new https://www.360docs.net/doc/9e14186448.html,ponentModel.Converter.NumberTypeConverter(typeof(double),

"#,###.00");

//字符串单元格

grid1[0, 0] = new SourceGrid.Cells.Cell(9419.3894);

grid1[0, 0].Editor = editorDouble;我已经用TypeConverter 属性定制了转换为字符串值, 以及从字符串转换的过程。

有许多其他的类型转换(TypeConverter)可用:

https://www.360docs.net/doc/9e14186448.html,ponentModel.Converter.NumberTypeConverter - 用于数值型, 如: double, decimal, int, float

https://www.360docs.net/doc/9e14186448.html,ponentModel.Converter.PercentTypeConverter - 用于以百分比格式表示的数值型, 如: double, decimal 和float.

https://www.360docs.net/doc/9e14186448.html,ponentModel.Converter.CurrencyTypeConverter - 用于以货币格式表示的Decimal 和double 类型.

https://www.360docs.net/doc/9e14186448.html,ponentModel.Converter.DateTimeTypeConverter - DateTime 类型.

下面是建立定制格式的DateTime 编辑器的另一个实例:

//有定制格式的DateTime 编辑器

string[] dtParseFormats = new string[] { dtFormat2 };

System.Globalization.DateTimeStyles dtStyles = System.Globalization.DateTimeStyles.AllowInnerWhite |

System.Globalization.DateTimeStyles.AllowLeadingWhite |

System.Globalization.DateTimeStyles.AllowTrailingWhite |

System.Globalization.DateTimeStyles.AllowWhiteSpaces; TypeConverter dtConverter = new https://www.360docs.net/doc/9e14186448.html,ponentModel.Converter.DateTimeTypeConverter(dtFormat2, dtParseFormats, dtStyles);

SourceGrid.Cells.Editors.TextBoxUITypeEditor editorDt2 = new SourceGrid.Cells.Editors.TextBoxUITypeEditor(typeof(DateTime));

editorDt2.TypeConverter = dtConverter;

grid[currentRow, 1] = new SourceGrid.Cells.Cell(DateTime.Today);

grid[currentRow, 1].Editor = editorDt2;

下图表示大部份可用的编辑器和一些特定单元格(图片从例 3 取得):

以用户控件或特定行为的少量代码行, 来建立一个定制的编辑器(Editor)是可行的。

你可以从EditorControlBase 派生自定义类, 并建立任何Windows 窗体控件。下面是使用DateTimePicker 控件的一个编辑器的示例:

public class DateTimePicker : EditorControlBase

{

public DateTimePicker():base(typeof(System.DateTime))

{

}

protected override Control CreateControl()

{

System.Windows.Forms.DateTimePicker dtPicker =

new System.Windows.Forms.DateTimePicker();

dtPicker.Format = DateTimePickerFormat.Short;

dtPicker.ShowCheckBox = AllowNull;

return dtPicker;

}

protected override void OnChanged(EventArgs e)

{

base.OnChanged(e);

if (Control != null)

Control.ShowCheckBox = AllowNull;

}

public new System.Windows.Forms.DateTimePicker Control

{

get

{

return (System.Windows.Forms.DateTimePicker)base.Control;

}

}

protected override void OnStartingEdit(CellContext cellContext,

Control editorControl)

{

base.OnStartingEdit(cellContext, editorControl);

System.Windows.Forms.DateTimePicker dtPicker =

(System.Windows.Forms.DateTimePicker)editorControl;

dtPicker.Font = cellContext.Cell.View.Font;

}

public override void SetEditV alue(object editV alue)

{

if (editV alue is DateTime)

Control.V alue = (DateTime)editV alue;

else if (editV alue == null)

Control.Checked = false;

else

throw new SourceGridException

("Invalid edit value, expected DateTime");

}

public override object GetEditedV alue()

{

if (Control.Checked)

return Control.V alue;

else

return null;

}

protected override void OnSendCharToEditor(char key)

{

}

}

思考:对于有许多单元格但只有一个网格控件时, 你可以共用同一个编辑器的实例。基本上每个编辑器都只与一个网格相关。

因为每个编辑器只与一个Windows 窗体控件相关(因此它是非常繁重的?), 所以对于大型网格,共用编辑器总是一个好主意.

11.高级单元格应用

命名空间: SourceGrid.Cells

可用的默认单元格有:

SourceGrid.Cells.Virtual ——此命名空间包含可以与GridVirtual 控件一起使用的所有的虚单元格。

CellVirtual - 基本单元格;用于大部分常规的虚单元格类型.

Header - 标头单元格.

ColumnHeader - 列头单元格.

RowHeader - 行头单元格.

Button - 按钮单元格.

CheckBox - 复选框单元格.

ComboBox - 组合框单元格

Link - 链接风格的单元格.

Image - 图象单元格.

SourceGrid.Cells ——此命名空间包含可以与Grid 控件一起使用的所有的实体单元格.

Cell - 所有其他类型的基本单元格, 用于最普通类型的实体单元格。

Header - 标头单元格.

ColumnHeader - 列头单元格.

RowHeader - 行头单元格.

Button - 按钮单元格.

CheckBox - 复选框单元格.

ComboBox - 组合框单元格.

Link - 链接风格的单元格.

Image - 图象单元格.

这些类的目的是简化外观(View)、模式(Model)、控制器(Controller)和编辑器(Editor)类的使用。如果我们看一下任一个单元格类的代码, 我们就能明白这些类是按照单元格的角色使用这些组件的。

举例来说,SourceGrid.Cells.CheckBox 单元格的代码如下:

public class CheckBox : Cell

{

public CheckBox(string caption, bool checkV alue):base(checkValue)

{

if (caption != null && caption.Length > 0)

View = Views.CheckBox.MiddleLeftAlign;

else

View = Views.CheckBox.Default;

Model.AddModel(new Models.CheckBox());

AddController(Controllers.CheckBox.Default);

AddController(Controllers.MouseInvalidate.Default);

Editor = new Editors.EditorBase(typeof(bool));

Caption = caption;

}

private Models.CheckBox CheckBoxModel

{

get{return

(Models.CheckBox)Model.FindModel(typeof(Models.CheckBox));}

}

public bool Checked

{

get{return CheckBoxModel.GetCheckBoxStatus(this, Range.Start).Checked;}

set{CheckBoxModel.SetCheckedV alue(this, Range.Start, value);}

}

public string Caption

{

get{return CheckBoxModel.Caption;}

set{CheckBoxModel.Caption = value;}

}

}

12.焦点和选区

一个单元格能被选定, 或者能取得焦点。当许多单元格被选中的时候, 只有一个单元格能取得被Grid.Selection.ActivePosition 属性标识的焦点。在网格的Selection 对象中, 有一个单元格被选中。

取得焦点的单元格接收所有的鼠标和键盘事件, 选中单元格可以接收复制、粘贴和清除的操作。

你可以使用Grid.Selection.Focus(Position pos) 方法设置焦点到指定的单元格上, 使用输入的单元格位置将获取焦点, 使用Position.Empty 作为参数则移除焦点. 使用Grid.Selection.SelectCell 方法或SelectRange 方法增加指定单元格到选区, 或从选区移除单元格

要列示所有选中的单元格, 你可以使用Grid.Selection.GetRanges() 方法返回选区的列表, 或使用IsSelectedCell 方法检查特定的单元格是否被选中. 通过使用Grid.Selection.BackColor, Grid.Selection.Border, Grid.Selection.FocusBackColor 等属性,你可以定制选区的各种外观.

你也可以使用这些事件响应用户的特定操作: Grid.Selection.FocusRowEntered, Grid.Selection.FocusRowLeaving, Grid.Selection.FocusColumnEntered, Grid.Selection.FocusColumnLeaving, Grid.Selection.CellLostFocus, Grid.Selection.CellGotFocus, Grid.Selection.SelectionChanged, ...

你可以使用Grid.SelectionMode 属性设定选区的模式。可用的选项有: GridSelectionMode.Cell, GridSelectionMode.Row 和GridSelectionMode.Column. 这样,你就能设置网格选中整行、整列, 或者只是一个单元格。

允许或禁止多个选区, 必须使用Grid.Selection.EnableMultiSelection 属性. 按下Ctrl 或Shift 键, 你可以使用鼠标选中多个单元格。

13.Position 和Range 结构

项目中最常用的 2 个对象是结构Position 和Range. 结构Position 以一个行(Row)和一个列(Column) 标识位置, 结构Range 从一个起始Position 和一个结

束Position 标识一组单元格.

你可以使用grid.PositionToRectangle 方法读取指定单元格的实际位置. 因此产生的矩形相对于网格的用户区域。你可以使用grid.PointToScreen 把产生的矩形转换为绝对的屏幕坐标.

你可以使用grid.PositionAtPoint 方法, 为特定的用户区域点(Point)获取位置(Position).

14.CellContext结构

CellContext 是由一个Cell 和一个Position 组成的结构, 包含所有操作单元格的方法.

最重要的方法是:

StartEdit/EndEdit ——在特定的单元格上开始/停止编辑

DisplayText ——返回单元格的文本(string)

V alue ——返回单元格的值(object)

下面是一个普通的示例,演示如何使用CellContext 类:

SourceGrid.CellContext context = new SourceGrid.CellContext(grid, new SourceGrid.Position(r, c));

context.V alue = "hello";

context.StartEdit();

通常以一个CellContext 实例作为controller 事件的参数被自动创建,这样你总是可以访问主要的单元格属性。

15.高级功能

15.1使用边框(Border)

每个View 类都有一个DevAge.Drawing.IBorder 类型的Border 属性. DevAge.Drawing.IBorder 是一个泛型接口, 可用于绘制单元格的边框.

通常IBorder 接口被DevAge.Drawing.RectangleBorder 结构执行.

下面是一个改变单元格边框的示例:

DevAge.Drawing.Border border = new DevAge.Drawing.Border(Color.Red, 1); DevAge.Drawing.RectangleBorder cellBorder = new DevAge.Drawing.RectangleBorder(border, border);

SourceGrid.Cells.Views.Cell view = new SourceGrid.Cells.Views.Cell();

view.Border = cellBorder;

grid[r, c].View = view;

默认的边框设置只是右边框和底边框, 这样, 当有一组单元格时, 你会看见一个双边框.

你也可以使用Grid.BorderStyle 属性设置网格的边框.

15.2使用单元格提示条(ToolTip)

你可以在每个单元格上绑定一个提示条(ToolTip). 必须建立一个SourceGrid.Cells.Controllers.ToolTipText 控制器, 并把它关联到单元格中.示例如下:

SourceGrid.Cells.Controllers.ToolTipText toolTipController = new SourceGrid.Cells.Controllers.ToolTipText();

toolTipController.ToolTipTitle = "ToolTip example";

toolTipController.ToolTipIcon = https://www.360docs.net/doc/9e14186448.html,;

toolTipController.IsBalloon = true;

grid1[r, c] = new SourceGrid.Cells.Cell("Hello");

grid1[r, c].ToolTipText = "Example of tooltip, bla bla bla ....";

grid1[r, c].AddController(toolTipController);

单元格的ToolTipText 属性自动把一个SourceGrid.Cells.Models.IToolTipText 接口绑定到标准单元格上.

备注: 在GridVirtual 上使用提示条, 必须定义自己的

SourceGrid.Cells.Models.IToolTipText 执行, 从数据源中读取数据, 然后添加控制器和模式到虚单元格.

15.3使用上下文菜单(ContextMenu)

使用下列代码, 你可以为单元格建立一个上下文菜单(快捷菜单) . 首先以ContextMenu 定义一个控制器(controller):

//以ContextMenu 定义一个controller

public class PopupMenu : SourceGrid.Cells.Controllers.ControllerBase

{

ContextMenu menu = new ContextMenu();

public PopupMenu()

{

menu.MenuItems.Add("Menu 1", new EventHandler(Menu1_Click));

menu.MenuItems.Add("Menu 2", new EventHandler(Menu2_Click));

}

public override void OnMouseUp(SourceGrid.CellContext sender, MouseEventArgs e)

{

base.OnMouseUp (sender, e);

if (e.Button == MouseButtons.Right)

menu.Show(sender.Grid, new Point(e.X, e.Y));

}

private void Menu1_Click(object sender, EventArgs e)

{

//TODO Y our code here

}

private void Menu2_Click(object sender, EventArgs e)

{

//TODO Y our code here

}

}

然后增加控制器到单元格中:

PopupMenu menuController = new PopupMenu();

...

grid1[r, c] = new SourceGrid.Cells.Cell("Hello");

grid1[r, c].AddController(menuController);

15.4剪贴板操作(Clipboard)

SourceGrid 支持剪贴板复制, 粘贴和剪切操作. 使用下面代码允许使用这些功能:

grid1.ClipboardMode = SourceGrid.ClipboardMode.All;

用户可以使用Ctrl+C, Ctrl+V , Ctrl+X 键复制, 粘贴和剪切选定单元格, 使用Delete 键清除单元格内容.

15.5拖放操作(drag and drop)

不被支持: 从 4.5 版开始, 拖放(drag and drop)不再被支持, 我将尝试以后再次增加此功能.

16.使用建议

通常, 使用SourceGrid 时, 你必须以代码完成所有工作, 为此, 一个重要的建议是以一种良好的可重用的习惯组织代码.下面是一些小贴士:

如果你需要定制某些单元格的外观, 建议建立一个新类, 并在此类编写定制代码.

以这种习惯, 你可以在所有应用程序和窗体中重用类. 举例来说, 假如你需要指定所有单元格的背景色为灰色, 可以新建下面的类:

public class GrayView : SourceGrid.Cells.Views.Cell

{

public new static readonly GrayView Default = new GrayView();

public GrayView()

{

BackColor = Color.LightGray;

}

}

public class GrayCell : SourceGrid.Cells.Cell

{

public GrayCell(object val):base(val)

{

View = GrayView.Default;

}

}

此规则可以应用在网格的任何外观, 举例来说, 你可以建立一个新的Controller 类, 并在单元格中使用它

我们可以在上面的代码中看到的另一个重要的特色是, 我从一个static 变量指定了View 属性. 以这种方式, 你可以共用相同的实例到众多单元格中, 使系统资源最优化.

另一个小建议是关于使用命名空间的. 许多SourceGrid 类与系统类有着相同的名称. 举例来说, 有一个CheckBox 单元格, System.Windows.Forms 中CheckBox 控件与此同名, 出于此种原因, 某一时刻正常使用using 语句有些困难. 如果你不喜欢使用长命名空间, 希望可读性更好的代码, 我建议在using 语句中改变命名空间的名称. 举例来说, 你可以把下列代码:

SourceGrid.Cells.Button bt = new SourceGrid.Cells.Button();

替换为::

using Cells = SourceGrid.Cells;

.................

Cells.Button bt = new Cells.Button();

17.扩展功能

另外, 默认的Grid 控件有一些控件功能, 可用于某些情况. 你可以直接使用这些扩展功能之一, 或复制代码建立你自己的扩展功能.

相关主题
相关文档
最新文档