现在的位置: 首页 > 综合 > 正文

c# xptable NET中最强,最全功能的表格控件

2013年08月22日 ⁄ 综合 ⁄ 共 11771字 ⁄ 字号 评论关闭
由于项目需要,我需要定制一个ListView,它必须能够在列中插入图像、下拉框、可上下调整的数字、进度条等等。于是本文产生了...

[翻译]

Mathew Hall.著XPTable - .NET ListView meets Java's JTable

[简介]

由于项目需要,我需要定制一个ListView,它必须能够在列中插入图像、下拉框、可上下调整的数字、进度条等等。由于已经有了一个Java下的背景,我将简单地基于那个JTable封装。

XPTable

[功能]

全定制可视化界面
支持XP风格
轻易添加再定制的控件
可隐藏列
行、列、单元可以被Disable
每个单元、列可以有Tooltip
等等……

[XPTable]

XPTable包含下面的组件:
1. Table,
2. ColumnModel 和它的 Columns,
3. TableModel 和它的 Row 和 Cell,
4. Renderer
5. Editor

[控件使用]

首先加载控件到Toolbox上(添加一个Item,引用XPTable.dll

然后,拖动Table, ColumnModel 和 TableModel到Form上,设置Table的ColumnModel 和 TableModel属性,添加Column到ColumnModel,添加Row 和 Cell到TableModel.

image

或者,直接使用代码设定:

Table table = new Table();
ColumnModel columnModel = new ColumnModel();
TableModel tableModel = new TableModel();

// set the Table's ColumModel and TableModel
table.ColumnModel = columnModel;
table.TableModel = tableModel;

// add some Columns to the ColumnModel
columnModel.Columns.Add(new TextColumn("Text"));
columnModel.Columns.Add(new CheckBoxColumn("CheckBox"));
columnModel.Columns.Add(new ButtonColumn("Button"));

// add some Rows and Cells to the TableModel
tableModel.Rows.Add(new Row());
tableModel.Rows[0].Cells.Add(new Cell("Text 1"));
tableModel.Rows[0].Cells.Add(new Cell("CheckBox 1", true));
tableModel.Rows[0].Cells.Add(new Cell("Button 1"));
tableModel.Rows.Add(new Row());
tableModel.Rows[1].Cells.Add(new Cell("Text 2"));
tableModel.Rows[1].Cells.Add(new Cell("CheckBox 2", false));
tableModel.Rows[1].Cells.Add(new Cell("Button 2"));

[color=green]Table[/color]

Table是一个简单的对象,事实上,它并不知道如何显示数据。而是,分别使用ColumnModel 和TableModel 控制列和单元等等。 Table的主要角色是管理绘制操作,传递事件给Renderer 和 Editor,以控制其行为。

ColumnModel

ColumnModel包含一个列的集合,这些列会在Table上显示。它会跟踪创建到指定列的CellRenderer CellEditor

TableModel

它包含即将显示的Row集合。

Renderers

就象上面说的那样,Table 并不知道如何绘制单元或列头。想法,它使用称为Renderers 的对象绘制这些。

Table 使用两个不同类型的Render,一个是Renderers: CellRenderer 绘制Cell,还一个HeaderRenderer绘制Column Header。

CellRenderers

下面是所有XPTable提供的CellRenderer:
* ICellRenderer - Exposes common methods provided by Cell renderers.
* CellRenderer - Base class for all Cell renderers.
* TextCellRenderer - A CellRenderer that draws Cell contents as strings.
* ButtonCellRenderer - A CellRenderer that draws Cell contents as Buttons.
* CheckBoxCellRenderer - A CellRenderer that draws Cell contents as CheckBoxes.
* ImageCellRenderer - A CellRenderer that draws Cell contents as Images.
* NumberCellRenderer - A CellRenderer that draws Cell contents as numbers.
* ProgressBarCellRenderer - A CellRenderer that draws Cell contents as a ProgressBar.
* DropDownCellRenderer - Base class for CellRenderers that draw Cell contents like ComboBoxes.
* ComboBoxCellRenderer - A CellRenderer that draws Cell contents as a ComboBox.
* ColorCellRenderer - A CellRenderer that draws Cell contents as Colors.
* DateTimeCellRenderer - A CellRenderer that draws Cell contents as a DateTime.

每个CellRenderer的默认输出如下:

image

定制CellRenderer

有两种方法定制CellRenderer,一是继承CellRenderer ,重写其OnPaint 和 OnPaintBackground方法;另一种方法是实现ICellRenderer (需要做的比较多)。

下面是Table的内建TextCellRenderer的代码:

public class TextCellRenderer : CellRenderer
{
protected override void OnPaint(PaintCellEventArgs e)
{
base.OnPaint(e);

// don't bother going any further if the Cell is null
if (e.Cell == null)
{
return;
}

// make sure we have some text to draw
if (e.Cell.Text != null && e.Cell.Text.Length != 0)
{
// check whether the cell is enabled
if (e.Enabled)
{
e.Graphics.DrawString(e.Cell.Text, base.Font,
base.ForeBrush, base.ClientRectangle,
base.StringFormat);
}
else
{
e.Graphics.DrawString(e.Cell.Text, base.Font,
base.GrayTextBrush, base.ClientRectangle,
base.StringFormat);
}
}

// draw a focus rect around the cell if it is
// enabled and has focus
if (e.Focused && e.Enabled)
{
ControlPaint.DrawFocusRectangle(e.Graphics,
base.ClientRectangle);
}
}
}

HeaderRenderers

和CellRenderer不一样,HeaderRenderer 绘制所有的列Header。

XPTable提供的HeaderRenderer有:

* IHeaderRenderer - Exposes common methods provided by Column header renderers.
* HeaderRenderer - Base class for Renderers that draw Column headers.
* XPHeaderRenderer - A HeaderRenderer that draws Windows XP themed Column headers.
* GradientHeaderRenderer - A HeaderRenderer that draws gradient Column headers.
* FlatHeaderRenderer - A HeaderRenderer that draws flat Column headers.

下图显示了内建的HeaderRenderer的动作:

image

可以通过下面的语句进行具体的指定:

Code:

// get the table to use a FlatHeaderRenderer
// to draw the column headers
table.HeaderRenderer = new FlatHeaderRenderer();

定制HeaderRenderer

下面是内建的XPHeaderRenderer的代码:

public class XPHeaderRenderer : HeaderRenderer
{
protected override void OnPaintBackground(PaintHeaderEventArgs e)
{
base.OnPaintBackground(e);

if (e.Column == null)
{
ThemeManager.DrawColumnHeader(e.Graphics, e.HeaderRect,
ColumnHeaderStates.Normal);
}
else
{
ThemeManager.DrawColumnHeader(e.Graphics, e.HeaderRect,
(ColumnHeaderStates) e.Column.ColumnState);
}
}


protected override void OnPaint(PaintHeaderEventArgs e)
{
base.OnPaint(e);

// don't bother if we don't have a column
if (e.Column == null)
{
return;
}

Rectangle textRect = base.ClientRectangle;
Rectangle imageRect = Rectangle.Empty;

// check whether we can draw an image on the column header
if (e.Column.Image != null)
{
imageRect = base.CalcImageRect();
textRect.Width -= imageRect.Width;
textRect.X += imageRect.Width;

if (e.Column.ImageOnRight)
{
imageRect.X = base.ClientRectangle.Right - imageRect.Width;
textRect.X = base.ClientRectangle.X;
}

// column headers that aren't themed and are pressed need
// their contents shifted down and to the right by 1 pixel
if (!ThemeManager.VisualStylesEnabled &&
e.Column.ColumnState == ColumnState.Pressed)
{
imageRect.X += 1;
imageRect.Y += 1;
}

base.DrawColumnHeaderImage(e.Graphics, e.Column.Image,
imageRect, e.Column.Enabled);
}

// column headers that aren't themed and are pressed need
// their contents shifted down and to the right by 1 pixel
if (!ThemeManager.VisualStylesEnabled &&
e.Column.ColumnState == ColumnState.Pressed)
{
textRect.X += 1;
textRect.Y += 1;
}

// check whether we need to draw a sort arrow
if (e.Column.SortOrder != SortOrder.None)
{
// work out where to draw it
Rectangle arrowRect = base.CalcSortArrowRect();

// adjust the textRect to take the arrow into account
arrowRect.X = textRect.Right - arrowRect.Width;
textRect.Width -= arrowRect.Width;

base.DrawSortArrow(e.Graphics, arrowRect, e.Column.SortOrder,
e.Column.Enabled);
}

// check whether we have any text to draw
if (e.Column.Text == null)
{
return;
}

if (e.Column.Text.Length > 0 && textRect.Width > 0)
{
if (e.Column.Enabled)
{
e.Graphics.DrawString(e.Column.Text,
base.Font, base.ForeBrush,
textRect, base.StringFormat);
}
else
{
using (SolidBrush brush =
new SolidBrush(SystemPens.GrayText.Color))
{
e.Graphics.DrawString(e.Column.Text,
base.Font, brush,
textRect, base.StringFormat);
}
}
}
}
}

Editors

5个内建的编辑器如下:

* ICellEditor - Exposes common methods provided by Cell editors.
* CellEditor - Base class for Cell editors.
* TextCellEditor - A class for editing Cells that contain strings.
* NumberCellEditor - A class for editing Cells that contain numbers.
* DropDownCellEditor - Base class for editing Cells that contain drop down buttons.
* ComboBoxCellEditor - A class for editing Cells that look like a ComboBox.
* ColorCellEditor - A class for editing Cells that contain Colors.
* DateTimeCellEditor - A class for editing Cells that contain DateTimes.
* IEditorUsesRendererButtons - Specifies that a CellEditor uses the buttons provided by its counter-part CellRenderer during editing.

见下图:

image

按下面的代码,编辑一个单元:

Code:

// start editing the cell at (0, 0)
table.EditCell(0, 0);

// stop editing the cell and commit any changes
table.StopEditing();

// or cancel editing and ignore any changes
table.CancelEditing();

定制CellEditor

下面是内建的TextCellEditor的代码:

public class TextCellEditor : CellEditor
{
public TextCellEditor() : base()
{
TextBox textbox = new TextBox();
textbox.AutoSize = false;
textbox.BorderStyle = BorderStyle.None;

base.Control = textbox;
}


// Sets the location and size of the CellEditor
protected override void SetEditLocation(Rectangle cellRect)
{
this.TextBox.Location = cellRect.Location;
this.TextBox.Size = new Size(cellRect.Width-1,
cellRect.Height-1);
}


// Sets the initial value of the
// editor based on the contents of
// the Cell being edited
protected override void SetEditValue()
{
this.TextBox.Text = base.EditingCell.Text;
}


// Sets the contents of the Cell
// being edited based on the value
// in the editor
protected override void SetCellValue()
{
base.EditingCell.Text = this.TextBox.Text;
}


// Starts editing the Cell
public override void StartEditing()
{
this.TextBox.KeyPress +=
new KeyPressEventHandler(OnKeyPress);
this.TextBox.LostFocus +=
new EventHandler(OnLostFocus);

base.StartEditing();

this.TextBox.Focus();
}


// Stops editing the Cell and commits any changes
public override void StopEditing()
{
this.TextBox.KeyPress -=
new KeyPressEventHandler(OnKeyPress);
this.TextBox.LostFocus -=
new EventHandler(OnLostFocus);

base.StopEditing();
}


// Stops editing the Cell and ignores any changes
public override void CancelEditing()
{
this.TextBox.KeyPress -=
new KeyPressEventHandler(OnKeyPress);
this.TextBox.LostFocus -=
new EventHandler(OnLostFocus);

base.CancelEditing();
}


// Gets the TextBox used to edit the Cells contents
public TextBox TextBox
{
get
{
return base.Control as TextBox;
}
}


// Handler for the editors TextBox.KeyPress event
protected virtual void OnKeyPress(object sender,
KeyPressEventArgs e)
{
// check whether we nned to stop or cancel editing
if (e.KeyChar == AsciiChars.CarriageReturn /*Enter*/)
{
if (base.EditingTable != null)
{
base.EditingTable.StopEditing();
}
}
else if (e.KeyChar == AsciiChars.Escape)
{
if (this.EditingTable != null)
{
base.EditingTable.CancelEditing();
}
}
}


// Handler for the editors TextBox.LostFocus event
protected virtual void OnLostFocus(object sender,
EventArgs e)
{
// if the textbox loses focus
// we should stop editing
if (base.EditingTable != null)
{
base.EditingTable.StopEditing();
}
}
}

风格

下面的代码显示如何共享CellStyle 和 Rowstyle:

// create a new CellStyle object
CellStyle cellStyle = new CellStyle();
cellStyle.BackColor = Color.Blue;
cellStyle.ForeColor = Color.Red;
cellStyle.Font = new Font("Tahoma", 8.25f, FontStyle.Bold);

// create a new RowStyle object
RowStyle rowStyle = new RowStyle();
rowStyle.BackColor = Color.Yello;
rowStyle.ForeColor = Color.Green;
rowStyle.Font = new Font("Arial", 8.25f, FontStyle.Italics);

for (int i=0; i<3; i++)
{
tableModel.Rows[i].RowStyle = rowStyle;

// only set the cellstyle for cells in the 3rd column
tableModel[i, 2].CellStyle = cellStyle;
}

排序

排序是基于列的,当点击在Header的时候,执行。

有六种内建的比较器:

* ComparerBase - Base class for Cell comparers.
* TextComparer - for comparing Cells based on the Text property.
* CheckBoxComparer - for comparing Cells based on the Checked property.
* NumberComparer - for comparing Cells that contain numbers in the Data property.
* ImageComparer - for comparing Cells based on the Image property.
* ColorComparer - for comparing Cells that contain Colors in the Data property.
* DateTimeComparer - for comparing Cells that contain DateTimes in the Data property.

四种排序机制:

* InsertionSorter
* MergeSorter
* ShellSorter
* HeapSorter

你可以通过调用table的Sort 方法对一列进行排序:

// sort the currently sorted column in the opposite direction
// to its currnent sort order, or if no columns are sorted, the
// column that has focus in ascending order
table.Sort();

// sort the currently sorted column in the opposite direction
// to its currnent sort order, or if no columns are sorted, the
// column that has focus in ascending order using an unstable
// sort method
table.Sort(false);

// sort the column at index 3 in the table's ColumnModel
// opposite to its current sort order, or in ascending order
// if the column is not sorted
table.Sort(3);

// sort the column at index 3 in the table's ColumnModel
// opposite to its current sort order, or in ascending order
//if the column is not sorted using a stable sort method
table.Sort(3, true);

// sort the column at index 3 in the table's ColumnModel
// in descending order
table.Sort(3, SortOrder.Descending);

// sort the column at index 3 in the table's ColumnModel
// in ascending order using an unstable sort method
table.Sort(3, SortOrder.Ascending, false);

还可以设置属性,不允许排序:

Code:

// disable sorting for a column
column.Sortable = false;

定制比较器

public class TextComparer : ComparerBase
{
// Compares two objects and returns a
// value indicating whether one is less
// than, equal to or greater than the other
public override int Compare(object a, object b)
{
Cell cell1 = (Cell) a;
Cell cell2 = (Cell) b;

// check for null cells
if (cell1 == null && cell2 == null)
{
return 0;
}
else if (cell1 == null)
{
return -1;
}
else if (cell2 == null)
{
return 1;
}

// check for null data
if (cell1.Text == null && cell2.Text == null)
{
return 0;
}
else if (cell1.Text == null)
{
return -1;
}

// now that we know both cells contain valid data,
// use the frameworks built in string comparer
return cell1.Text.CompareTo(cell2.Text);
}
}

被选单元Selections

被选中的单元通常会被高亮:

image

你可以设置这个风格:

Code:

// use grid style selection
table.SelectionStyle = SelectionStyle.Grid;

即将增加的功能

* Word wrapping for cells and column headers
* Autosizing rows and columns
* Variable height rows
* LinkLabel cells
* RichTextFormat cells
* Dialog based CellEditors
* ListView style icon mode
* RightToLeft support
* Cut and paste support
* Drag and drop support
* Data binding
* Column re-ordering
* Printing support
* Export to HTML and XML
* Serialization
* Other stuff I've forgotten or haven't thought of yet

抱歉!评论已关闭.