|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
ContentsIntroductionFor a project I'm working on I needed a highly customized Features
XPTable
I'm not going to go into much detail about the first three points and will only show the basics for points 4 and 5 as otherwise this article would be much larger than it already is. If you want more details on any of these topics then you should read the User Guide supplied with the documentation. Using XPTableBefore using the To add the XPTable.dll to the toolbox, you can either:
and browse for XPTable.dll and then press OK. You can then drag the controls onto your Form. Note: If you recompile the source code you will need to re-sign XPTable.dll, as otherwise Visual Studio may throw an exception when you attempt to add it to the toolbox.
You should then be able to add it to the toolbox. After that, all you need to do is drag a
or if you prefer code: 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"));
TableA ColumnModelA ColumnsAfter thinking for a while about the best way to implement
TableModelA RowsA CellsA RenderersAs mentioned earlier, a A CellRenderers
The list below shows all the
The image below shows the default output of each
Creating a custom CellRendererIf you want to create a custom Below is the code for the 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);
}
}
}
For a more complex example, see the User Guide provided with the documentation. HeaderRenderersUnlike The list below shows all the
The image below shows the built in
You can specify the // get the table to use a FlatHeaderRenderer
// to draw the column headers
table.HeaderRenderer = new FlatHeaderRenderer();
Creating a custom HeaderRendererIf you want to create a custom Below is the code for the 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
Note: For more information about The image below shows the editors that use a drop-down control to edit
You can programmatically edit a // 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();
Note: If you want to stop or cancel editing always use the Creating a custom CellEditorIf you want to create a custom Below is the code for the 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();
}
}
}
Visual stylesWith
CellStyles
Note: Setting one of these values on a RowStyles
Table stylesIn this version
Note: The example below shows how // 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;
}
SortingSorting a table is performed on a per-column basis, and can be initiated by clicking on a There are six inbuilt comparers:
There are also four inbuilt sorters:
InsertionSort and MergeSort are considered to be stable sorts, whereas ShellSort and HeapSort are unstable. Also, InsertionSort and ShellSort are faster than MergeSort and HeapSort on smaller lists and slower on large lists. The actual algorithm used to sort a For more information on sorting methods and stable/unstable sorting refer to this site. You can programmatically sort a // 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);
Note: The You can disable // disable sorting for a column
column.Sortable = false;
Note: Setting the Creating a custom comparerIt is also possible to create a custom comparer for use by a 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);
}
}
SelectionsA
Top: ListView style selection Bottom: Grid style selection This can be set using the // use grid style selection
table.SelectionStyle = SelectionStyle.Grid;
Note: With The Future featuresBelow is a list of features that I would like to add to future versions:
History
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||