Introduction
SourceGrid
is a Windows Forms control written entirely in C#, my goal is to create a simple but flexible grid to use in all of the cases in which it is necessary to visualize or to change a series of data in a table format.
There are a lot of controls of this type available, but often are expensive, difficult to be customize or not compatible with. NET.
The Microsoft DataGrid
for me is too DataSet
orientated and therefore results often complicated to use in the cases in which the source data isn't a DataSet and often is not enough customizable.
I want to thank Chirs Beckett, Anthony Berglas, Wayne Tanner, Ernesto Perales, Vadim Katsman, Jeffery Bell, Gmonkey, cmwalolo, Kenedy, zeromus, Darko Damjanovic, John Pierre and a lot of other persons who helped me with code, bugs report and with new ideas and suggestions.
This control is compiled with the Microsoft Framework. NET 1.1 and reference the assembly SourceLibrary.dll 1.2.0.0, this is a small library with common functionality. I introduced this dll in the ZIP file, but is possible to download the entire code and the last binary from the site http://sourcegrid.codeplex.com/. For use SourceGrid is necessary have Visual Studio.NET 2003 or a compatible development environment.
The last version of this control is downloadable from site http://sourcegrid.codeplex.com/.
In this article I will want to supply a panoramic on the utilization and on the functionality of the control SourceGrid, for the details on the classes, properties or methods you can consult the documentation in CHM format or the example project in the ZIP file.
Use SourceGrid
In the assembly SourceGrid2.dll are present 2 controls that can be inserted in the Toolbox of Visual Studio and used in any Form
:
-
GridVirtual
- A grid of virtual cells (ICellVirtual)
.
-
Grid
- A grid of real cells (ICell)
.
There are therefore two fundamental distinctions to do: virtual cells and real cells. Virtual cells are the cells that determine the appearance and the behavior of the cell but don't contain the value, the real cells have the same properties of the virtual cells but contain also the value of the cell, they are therefore associated to a specific position of the grid.
Every cells are composed by three fundamental parts:
-
DataModel
: The DataModel is the class that manages the value of the cells. Converts the value of the cell in a string for visual representation, create the editor of the cell and validate the inserted values.
-
VisualModel
: The VisualModel is the class that draws the cell and contains the visual properties.
-
BehaviorModel
: The BehaviorModel is the class that supplies the behavior of the cell.
This subdivision grants a great flexibility and reusability of code, save time and supplies a solid base for every type of customizations.
For the more common cases there are some classes already arranged and configured, but with little lines of code is possible to create personalized cells (see the next paragraphs for the details).
Grid
The Grid
control is the ideal if you want the greatest flexibility and simplicity but with not many cells. In fact in this control every cells are represented by a .NET class and therefore occupies a specific quantity of resources. Moreover this is the only grid that supports features of RowSpan and ColumnSpan.
After to have inserted the control in the form we can begin to write our code to use the grid in the Load
event of the form like this:
grid1.Redim(2, 2);
grid1[0,0] = new SourceGrid2.Cells.Real.Cell("Hello from Cell 0,0");
grid1[1,0] = new SourceGrid2.Cells.Real.Cell("Hello from Cell 1,0");
grid1[0,1] = new SourceGrid2.Cells.Real.Cell("Hello from Cell 0,1");
grid1[1,1] = new SourceGrid2.Cells.Real.Cell("Hello from Cell 1,1");
The previous code creates a table with 2 lines and 2 columns (Redim
method) and populates every positions with a cell. I have used the SourceGrid2.Cells.Real
namespace where are present all the real cells.
Every cells contains all the necessary display properties, for example to change the background color of the cell we can write:
SourceGrid2.Cells.Real.Cell l_Cell = new SourceGrid2.Cells.Real.Cell(
"Custom back color");
l_Cell.BackColor = Color.LightGreen;
grid1[0,0] = l_Cell;
These are the main visual properties of a cell (for an entire list to consult the documentation of the grid): BackColor, ForeColor, Border, Font, TextAlignment, WordWrap ...
,
Now we try to create an entire grid with headers, automatic sort, resize of the columns with the mouse, string and DateTime editor and a checkbox.
grid1.BorderStyle = BorderStyle.FixedSingle;
grid1.ColumnsCount = 3;
grid1.FixedRows = 1;
grid1.Rows.Insert(0);
grid1[0,0] = new SourceGrid2.Cells.Real.ColumnHeader("String");
grid1[0,1] = new SourceGrid2.Cells.Real.ColumnHeader("DateTime");
grid1[0,2] = new SourceGrid2.Cells.Real.ColumnHeader("CheckBox");
for (int r = 1; r < 10; r++)
{
grid1.Rows.Insert(r);
grid1[r,0] = new SourceGrid2.Cells.Real.Cell("Hello "
+ r.ToString(), typeof(string));
grid1[r,1] = new SourceGrid2.Cells.Real.Cell(
DateTime.Today, typeof(DateTime));
grid1[r,2] = new SourceGrid2.Cells.Real.CheckBox(true);
}
grid1.AutoSizeAll();
In the previous code I have set the grid border, the number of columns, the number of fixed rows and created the first header row. For the header I have used a ColumnHeader
cell. With a simple cycle for I have then created the other cells using for each column a specific type. The Cell
class creates automatically an appropriate editor for the type specified (in this case a TextBox and a DateTimePicker). For the last column I have used a CheckBox
cell that allows the display of a checkbox directly on the cell.
The form should look equal to the one in the following figure, this example is present also in the project SampleProject with the ZIP file.
GridVirtual
The GridVirtual
control is the ideal when is necessary to visualize a lot of cells and you have already available a structure data like a DataSet
, an Array
, a document XML or other data structure.
This type of grid have the same features of the Grid
control except for the automatic sort (this because the grid cannot order automatically any external data structure without copying its content) and the feature of RowSpan and ColumnSpan that allow to span a cell across other adjacent cells.
Another disadvantage is that to create a virtual grid is a little difficult.
The main concept in a virtual grid is that the cells do not contain the values, but read and write the value in an external data structure. This idea was implemented with an abstract class CellVirtual
in which is necessary to redefine the methods GetValue
and SetValue.
To use the GridVirtual
is therefore necessary to create a class that derives from CellVirtual
and to personalize the reading using the data source chosen.
Usual is better to create also a control that derive from GridVirtual
, to have a greater flexibility and a more solid code, overriding the method GetCell
.
If you prefer you can directly use the GridVirtual
control and the event GettingCell
. The purpose of the method GetCell
and of the event GettingCell
is to return, for a given position (row and column), the chosen cell. This allows a large flexibility because you can return for a specific type any ICellVirtual
, for example you could return a cell of type header when the row is 0.
In the following example I create a virtual grid that reads and writes the values in an array. First I have inserted the control GridVirtual
in a form, then I write this code that defines our virtual class:
public class CellStringArray : SourceGrid2.Cells.Virtual.CellVirtual
{
private string[,] m_Array;
public CellStringArray(string[,] p_Array):base(typeof(string))
{
m_Array = p_Array;
}
public override object GetValue(SourceGrid2.Position p_Position)
{
return m_Array[p_Position.Row, p_Position.Column];
}
public override void SetValue(SourceGrid2.Position p_Position,
object p_Value)
{
m_Array[p_Position.Row, p_Position.Column] = (string)p_Value;
OnValueChanged(new SourceGrid2.PositionEventArgs(p_Position, this));
}
}
With the previous code I have created a virtual cell with an editor of type string
that reads and writes the values in an array specified in the constructor.
After the call to the SetValue
method we should call the OnValueChanged
method to notify the grid to update this cell.
In the event Load
of the Form
I have insert this code:
private void frmSample15_Load(object sender, System.EventArgs e)
{
gridVirtual1.GettingCell += new SourceGrid2.PositionEventHandler(
gridVirtual1_GettingCell);
gridVirtual1.Redim(1000,1000);
string[,] l_Array = new string[gridVirtual1.RowsCount,
gridVirtual1.ColumnsCount];
m_CellStringArray = new CellStringArray(l_Array);
m_CellStringArray.BindToGrid(gridVirtual1);
}
I have added an event handler to GettingCell
event, created the grid and the array with 1000 rows and 1000 columns, then I have created a new instance of the previous cell and with the method BindToGrid
I have linked the cell to the grid.
I have created a single cell that will be used for every position of the matrix. Is always necessary to call the method BindToGrid
on the cells that we want to use in a virtual grid.
In order to finish we should write the method GettingCell
and declare the variable for the cell:
private CellStringArray m_CellStringArray;
private void gridVirtual1_GettingCell(object sender,
SourceGrid2.PositionEventArgs e)
{
e.Cell = m_CellStringArray;
}
The result should look equal to the one in the following picture, this example is present also in the project SampleProject included in the ZIP file.
VisualModel
Namespace: SourceGrid2.VisualModels
Every cell have a property VisualModel
that returns an interface of type IVisualModel
. The cell uses this interface to draw and to customize the visual properties of the cell.
The purpose of the VisualModel
is to separate the drawing code from the rest of the code and allows to sharing the same visual model between more cells. In fact the same instance of VisualModel
can be used on more cells simultaneously optimizing the use of the resources of the system.
The default VisualModel
classes are read-only, however each VisualModel
is provided with a Clone
method that allows you to create identical instances of the same model.
These are the default VisualModel
classes in the namespace SourceGrid2.VisualModels:
-
SourceGrid2.VisualModels.Common
- Used for classic cells. In this model you can customize the colors, the font, the borders and a lot other properties.
-
SourceGrid2.VisualModels.CheckBox*
- Used for checkbox style cells. The checkbox can be selected, disabled and can contains a caption.
-
SourceGrid2.VisualModels.Header*
- Used for header style cells with 3D borders. You can configure the borders to gradually vanish from the color of the border to the color of the cell for a better three-dimensional effect.
-
SourceGrid2.VisualModels.MultiImages
- Allows to drawing more then one image in the cell.
*The VisualModel
marked with an asterisk require a special interface to work correctly, for example the CheckBox
model needs a cell that supports the ICellCheckBox
interface.
Each of these classes contains one or more static properties with some default read-only instances easily useable:
SourceGrid2.VisualModels.Common.Default
SourceGrid2.VisualModels.Common.LinkStyle
SourceGrid2.VisualModels.CheckBox.Default
SourceGrid2.VisualModels.CheckBox.MiddleLeftAlign
SourceGrid2.VisualModels.Header.Default
SourceGrid2.VisualModels.Header.ColumnHeader
SourceGrid2.VisualModels.Header.RowHeader
This code shows how to assign the same VisualModel
to more cells previously created and then change some properties:
SourceGrid2.VisualModels.Common l_SharedVisualModel =
new SourceGrid2.VisualModels.Common();
grid1[0,0].VisualModel = l_SharedVisualModel;
grid1[1,0].VisualModel = l_SharedVisualModel;
grid1[2,0].VisualModel = l_SharedVisualModel;
l_SharedVisualModel.BackColor = Color.LightGray;
Consider also that when you write Cell.BackColor
the property calls automatically the BackColor
property of the VisualModel
associated. To facilitate the utilization of the more common properties if you write Cell.BackColor = Color.Black;
the cell automatically clone the current VisualModel
, changes the backcolor to the cloned instance and assigns the cloned instance again to the cell.
DataModel
Namespace: SourceGrid2.DataModels
To represent the value of a cell in a string format and to supply a cell data editor, is necessary to populate the property DataModel
of the cell. If this property is null is not possible to change the value of the cell and the string conversion will be a simple ToString
of the value.
Usual a DataModel
use a TypeConverter
of the type asked to manage the necessary conversion, particularly the string conversion (used to represent the cell value).
These are the default DataModel
classes in the namespace SourceGrid2.DataModels:
-
DataModelBase
- Supplies the methods of conversion and allows the alteration of the cell value only by code, does not supply graphic interface. This class is the base of all the other editors and is used also to manage read-only cells but with customized formattings or special editors (for example the CheckBox cell use a read-only editor because the value is changed clicking directly on the checkbox).
-
EditorControlBase
- Abstract Class that help to use a control as editor for the cell.
-
EditorTextBox
- A TextBox editor. This is one of the more used editor by all types that support string conversion (string, int, double, enum,....)
-
EditorComboBox
- A ComboBox editor.
-
EditorDateTime
- A DateTimePicker editor.
-
EditorNumericUpDown
- A NumericUpDown editor.
-
EditorTextBoxButton
- A TextBox editor with a button to open a details mask.
-
EditorUITypeEditor
- Supplies the editing of the cell of all types that have an UITypeEditor
. A lot of types support this interface: DateTime, Font, a lot of enum, ...
A DataModel
can be shared between more cells, for example you can use the same DataModel
for every cell of a column.
To create an editable cell there are 2 possibilities:
-
Create the cell specifying the value type. In this manner the cell calls automatically an utility function,
Utility.CreateDataModel
, that returns a DataModel
in base to the type specified.
grid1[0,0] = new SourceGrid2.Cells.Real.Cell("Hello",
typeof(string));
-
Create separately the
DataModel
and then assign it to the cells:
SourceGrid2.DataModels.IDataModel l_SharedDataModel =
SourceGrid2.Utility.CreateDataModel(typeof(string));
grid1[0,0].DataModel = l_SharedDataModel;
grid1[1,0].DataModel = l_SharedDataModel;
This method is recommended when you want to use the same editor for more of cells.
If you need a greater control on the type of editor or there are special requirements is possible to create manually the editor class.
In this case for example I create manually the class EditorTextBox
and then I call the property MaxLength and CharacterCasing.
SourceGrid2.DataModels.EditorTextBox l_TextBox =
new SourceGrid2.DataModels.EditorTextBox(typeof(string));
l_TextBox.MaxLength = 20;
l_TextBox.AttachEditorControl(grid1);
l_TextBox.GetEditorTextBox(grid1).CharacterCasing =
CharacterCasing.Upper;
grid1[2,0].DataModel = l_TextBox;
Some properties are defined to a DataModel
level, while other to an editor control level, in this case the property CharacterCasing is defined to a TextBox
control level. To use these properties is necessary therefore to force a linking of the editor to the grid with the method AttachEditorControl
and then call the method GetEditorTextBox
to returns the instance of the TextBox
.
This mechanism is also useful for create special editor like the ComboBox editor. To insert a ComboBox you must write this code:
SourceGrid2.DataModels.EditorComboBox l_ComboBox =
new SourceGrid2.DataModels.EditorComboBox(
typeof(string),
new string[]{"Hello", "Ciao"},
false);
grid1[3,0].DataModel = l_ComboBox;
Of course is possible to create custom DataModel
editor with custom control or special behaviors.
In the following picture it is possible to observe most of the editors available and some options like image properties:
BehaviorModel
Namespace: SourceGrid2.BehaviorModels
Every cell have a collection of BehaviorModel
that you can read with the Behaviors
property. A BehaviorModel
is a class that characterizes the behavior of the cell. A model can be shared between more cells and allows a great flexibility and simplicity of any new feature.
These are the default classes of type BehaviorModel
:
SourceGrid2.BehaviorModels.Common
- Common behavior of a cell.
SourceGrid2.BehaviorModels.Header
- Behavior of a header.
SourceGrid2.BehaviorModels.RowHeader
- Behavior of a row header, with resize feature.
SourceGrid2.BehaviorModels.ColumnHeader
* - Behavior of a column header, with sort and resize feature. (need
ICellSortableHeader
)
SourceGrid2.BehaviorModels.CheckBox
* - Behavior of a CheckBox. (need
ICellCheckBox
)
SourceGrid2.BehaviorModels.Cursor
* - Allows to link a cursor to a specific cell. (need
ICellCursor
)
SourceGrid2.BehaviorModels.Button
- Behavior of a Button.
SourceGrid2.BehaviorModels.Resize
- Allows a cell to be resized with the mouse (this model is automatically used by header models).
SourceGrid2.BehaviorModels.ToolTipText
* - Allows to show a ToolTipText linked to a cell. (need
ICellToolTipText
)
SourceGrid2.BehaviorModels.Unselectable
- Blocks a cell to receive the focus.
SourceGrid2.BehaviorModels.ContextMenu
* - Allows to show a contextmenu linked to a cell. (need a
ICellContextMenu
)
SourceGrid2.BehaviorModels.CustomEvents
- Expose a list of events that you can use without deriving from a BehaviorModel
.
SourceGrid2.BehaviorModels.BindProperty
- Allows to link the value of a cell to an external property.
SourceGrid2.BehaviorModels.BehaviorModelGroup
- Allows to create a BehaviorModel
that automatically calls a list of BehaviorModel
, useful when a
behavior needs other behaviors to work correctly.
*The BehaviorModel
marked with an asterisk need special cells to complete their tasks, for example the class CheckBox
requires of a cell that supports the interface ICellCheckBox
.
Every class have some static properties that return a default instance of the class:
SourceGrid2.BehaviorModels.Common.Default
SourceGrid2.BehaviorModels.Button.Default
SourceGrid2.BehaviorModels.CheckBox.Default
SourceGrid2.BehaviorModels.ColumnHeader.SortableHeader
SourceGrid2.BehaviorModels.ColumnHeader.NotSortableHeader
SourceGrid2.BehaviorModels.Cursor.Default
SourceGrid2.BehaviorModels.Header.Default
SourceGrid2.BehaviorModels.Resize.ResizeHeight
SourceGrid2.BehaviorModels.Resize.ResizeWidth
SourceGrid2.BehaviorModels.Resize.ResizeBoth
SourceGrid2.BehaviorModels.RowHeader.Default
SourceGrid2.BehaviorModels.ToolTipText.Default
SourceGrid2.BehaviorModels.Unselectable.Default
In the following code example I create a BehaviorModel
that change the backcolor of the cell when the user moves the mouse over the cell.
public class CustomBehavior : SourceGrid2.BehaviorModels.BehaviorModelGroup
{
public override void OnMouseEnter(SourceGrid2.PositionEventArgs e)
{
base.OnMouseEnter (e);
((SourceGrid2.Cells.Real.Cell)e.Cell).BackColor = Color.LightGreen;
}
public override void OnMouseLeave(SourceGrid2.PositionEventArgs e)
{
base.OnMouseLeave (e);
((SourceGrid2.Cells.Real.Cell)e.Cell).BackColor = Color.White;
}
}
To use this BehaviorModel
insert in Load event of a form this code:
grid1.Redim(2,2);
CustomBehavior l_Behavior = new CustomBehavior();
for (int r = 0; r < grid1.RowsCount; r++)
for (int c = 0; c < grid1.ColumnsCount; c++)
{
grid1[r,c] = new SourceGrid2.Cells.Real.Cell("Hello");
grid1[r,c].Behaviors.Add(l_Behavior);
}
Cells
Namespace: SourceGrid2.Cells
These are the default cells available:
-
SourceGrid2.Cells.Virtual - This namespace contains all the virtual cells that can be used with a
GridVirtual
control, these are all abstract cells and you must derive from these cells to use your custom data source.
CellVirtual
- Base cell for each other implementation, use for the most common type of virtual cells.
Header
- A header cell.
ColumnHeader
- A column header cell.
RowHeader
- A row header cell.
Button
- A button cell.
CheckBox
- A checkbox cell.
ComboBox
- A combobox cell.
Link
- A link style cell.
-
SourceGrid2.Cells.Real - This namespace contains all the real cells that can be used with a
Grid
control.
Cell
- Base cell for each other implementation, use for the most common type of real cells.
Header
- A header cell.
ColumnHeader
- A column header cell.
RowHeader
- A row header cell.
Button
- A button cell.
CheckBox
- A checkbox cell.
ComboBox
- A combobox cell.
Link
- A link style cell.
The goal of these classes is to simplify the use of VisualModel, DataModel and BehaviorModel
. If we look at the code of any of these classes we can see that these classes use the previous models according to the role of the cell. There are however models that require special interfaces and in this case the cells implement all the required interfaces.
This is for example the code of the cell SourceGrid2.Cells.Real.CheckBox
:
public class CheckBox : Cell, ICellCheckBox
{
public CheckBox(string p_Caption, bool p_InitialValue)
{
m_Caption = p_Caption;
DataModel = new SourceGrid2.DataModels.DataModelBase(typeof(bool));
VisualModel = SourceGrid2.VisualModels.CheckBox.MiddleLeftAlign;
Behaviors.Add(BehaviorModels.CheckBox.Default);
Value = p_InitialValue;
}
public bool Checked
{
get{return GetCheckedValue(Range.Start);}
set{SetCheckedValue(Range.Start, value);}
}
private string m_Caption;
public string Caption
{
get{return m_Caption;}
set{m_Caption = value;}
}
public virtual bool GetCheckedValue(Position p_Position)
{
return (bool)GetValue(p_Position);
}
public virtual void SetCheckedValue(
Position p_Position, bool p_bChecked)
{
if (DataModel!=null && DataModel.EnableEdit)
DataModel.SetCellValue(this, p_Position, p_bChecked);
}
public virtual CheckBoxStatus GetCheckBoxStatus(Position p_Position)
{
return new CheckBoxStatus(DataModel.EnableEdit,
GetCheckedValue(p_Position), m_Caption);
}
}
As you can see the CheckBox
class simply use the models SourceGrid2.DataModels.DataModelBase(typeof(bool)), SourceGrid2.VisualModels.CheckBox.MiddleLeftAlign e BehaviorModels.CheckBox.Default
implements the ICellCheckBox
interface with its method GetCheckBoxStatus
.
The methods Checked, Caption, GetCheckedValue
and SetCheckedValue
are methods to simplify the editing of the value of the cell.
Structure of the Grid
Rows and Columns
The main components of a grid are the rows and the columns. To manipulate these informations SourceGrid supplies 2 properties:
Rows
- Returns a collection of type RowInfoCollection
that is a strip of classes RowInfo
.
Columns
- Returns a collection of type ColumnInfoCollection
that is a list of classes ColumnInfo
.
These are some of the RowInfo
class properties: Height, Top, Bottom, Index, Tag
. These are instead the properties of the ColumnInfo
class:Width, Left, Right, Index, Tag
.
There are many ways to manipulate rows and columns:
These three examples perform all the same task of creating a table with 2 rows and 2 columns.
To change the width or the height of a row or a column you can use this code:
grid1.Rows[0].Height = 100;
grid1.Columns[0].Width = 100;
The properties Top, Bottom, Left and Right
are automatically calculated using the width and the height of the rows and columns.
Panels
To manage correctly scrollbars, columns and rows fixed and a lot other details, the grid inside has a panels structure like this:
- 1)
TopLeftPanel
- Keeps fixed row and fixed column cells.
- 2)
TopPanel
- Keeps fixed rows.
- 3)
LeftPanel
- Keeps fixed columns.
- 4)
ScrollablePanel
- Keeps all not fixed cells.
- 5)
HScrollBar
- Horizontal ScrollBar
- 6)
VScrollBar
- Vertical ScrollBar.
- 7)
BottomRightPanel
- Panel to manage the small space between the two scrollbars.
Events
The mouse and keyboard events can be used with a BehaviorModel
or can be connected directly to the grid.
All the events are first fired to the panels and then automatically moved to GridVirtual
and Grid
control. To use these events you can write this code:
grid.MouseDown += new System.Windows.Forms.MouseEventHandler(
grid_MouseDown);
This can be done also with the Visual Studio designer.
Look at the example 8 in the project SampleProject for details.
ContextMenu
The grid has a default ContextMenu that can be customized with the ContextMenuStyle
property. It is possible to connect a ContextMenu to the Selection
object with the Grid.Selection.ContextMenuItems
, that will be used for all selected cells or otherwise you can connect a ContextMenu directly to a specific cell.
Look at the example 10 in the project SampleProject for further details.
Other Informations
Focus and Selection
A cell can be selected of can have the focus. Only one cell can have the focus, identified by the FocusCellPosition
property of the grid, instead many cells can be selected. A cell is selected when is present in the Selection
object of the grid.
The cell with the focus receives all of the mouse and keyboard events, while the selected cells can receive actions like the copy/paste.
Position and Range
Two of the most used objects in the project SourceGrid are the struct Position
and Range
. The struct Position
identifies a position with a Row and a Column, while the struct Range
identifies a group of cells delimited from a start Position
and an end Position
.
Performance
To optimize performance of this control use the GridVirtual
control when is necessary to visualize a lot of cells and try always to share the models (DataModel, VisualModel, BehaviorModel)
between more possible cells.
The performance of the grid is quite good even if the drawing code can be still optimized, especially when scrolling.
It is possible to consult the project SampleProject for further information on the performance of the grid.
Extensions
In the project SampleProject are present a lot of examples and parts of code that can give ideas or suggestions of how implements custom grid, particularly in the folder Extensions are present some grids that supply functionality like the binding to a DataSet
(DataTable)
, to an Array
and to an ArrayList.
Screenshots
How To
How to select an entire row:
grid1.Rows[1].Select = true;
How to select all the cells:
grid1.Selection.AddRange(grid1.CompleteRange);
How to create an editor with advanced validation rule:
grid1[0,0] = new SourceGrid2.Cells.Real.Cell(2, typeof(int));
grid1[0,0].DataModel.MinimumValue = 2;
grid1[0,0].DataModel.MaximumValue = 8;
grid1[0,0].DataModel.DefaultValue = null;
grid1[0,0].DataModel.AllowNull = true;
How to create a ComboBox editor to display a value different from the real used value, in this case is displayed a string while the real value is a double.
double[] l_RealValues = new double[]{0.0,0.5,1.0};
SourceGrid2.DataModels.EditorComboBox l_EditorCombo =
new SourceGrid2.DataModels.EditorComboBox(typeof(double));
l_EditorCombo.StandardValues = l_RealValues;
l_EditorCombo.StandardValuesExclusive = true;
l_EditorCombo.AllowStringConversion = false;
SourceLibrary.ComponentModel.Validator.ValueMapping l_Mapping =
new SourceLibrary.ComponentModel.Validator.ValueMapping();
l_Mapping.ValueList = l_RealValues;
l_Mapping.DisplayStringList = new string[]{"Zero", "One Half", "One"};
l_Mapping.BindValidator(l_EditorCombo);
grid1[0,0] = new SourceGrid2.Cells.Real.Cell(0.5, l_EditorCombo);
Features
What SourceGrid can do:
- It is possible to customize the graphic appearance, the type of editor and the behavior (cursor, tooltiptext, contextmenu ...,) of every cell.
- Supports natively all of the types of data that have a
TypeConverter
or an UITypeEditor
associated.
- Any .NET control can be used like editor with few lines of code.
- You can insert, delete and move rows and columns.
- The height and the width can be customized independently for every columns and rows or can be calculated automatic based to the content of the cells.
- Supports features of
RowSpan
and ColumnSpan
, to unite more cells.
- Supports automatic operations of Copy and Paste.
- Supports natively column sort.
- You can change the width and the height of the columns and rows.
- In every cell is possible to customize the image and the alignment of the text and the image.
- Supports MultiLine and WordWrap text.
- Supports an HTML export.
- With some extension supports data binding features.
- Support virtual cells used to binding any type of data source.
... and what cannot do
- SourceGrid doesn't have a designer, all should be done with code.
- No printing support.
Change SourceGrid code
It is allowed to change, recompile and to distribute the control SourceGrid for private and commercial use, I ask only to maintain the Copyright notes at the end of the page.
I recommend to change the file SourceGrid2.snk with a personalized version to not have problems of compatibility with different versions of the control. Consult MSDN for further information: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cptutorials/html/_4__A_Shared_Component.asp
Future developments
- Enhancement of the drawing code.
- Support for Masked Edit textbox.
Known problems
- There is not Cut support.
- The editor NumericUpDown is not aligned correctly to the cell.
- The Shift key does not work with the arrows keys and there are still some problems with header cells.
Previous versions
Version 2 of SourceGrid introduce many changes, and is not possible to list the all. The manner of utilization is very similar, but is not simple to convert a code written with previous versions.
These are some suggestions:
-
The major features of the grid work with the
ICellVirtual
interface, no more with Cell
class. This interface contains only necessary methods and therefore is poorer. For this the code that before was:
grid[0,0] = new SourceGrid.Cell("Ciao");
grid[0,0].BackColor = Color.White;
now should be transformed in
SourceGrid2.Cells.Real.Cell l_Cell =
new SourceGrid2.Cells.Real.Cell("Ciao");
l_Cell.BackColor = Color.White;
grid[0,0] = l_Cell;
- In the prior version the base cell was identified from the
Cell
class while now is the interface ICellVirtual
and the major change of this class is that does not contain informations about the position (row and column).
- A lot of the methods of the grid that before used the
Cell
type now use the Position
type, is however possible to extract the interface ICellVirtual
(and then cast to more specific interfaces) given a struct Position
with the method Grid.GetCell
- Now the grid support natively the property
BorderStyle
that is able therefore to eliminate the eventual Panel that before was necessary to introduce a border.
- All of the code that first was bound to the events of a cell now must be moved in a
BehaviorModel
, you can use for example the SourceGrid2.BehaviorModels.CustomEvents
.
- The
Selection
object is no more a collection of cells but a collection of Range
.
- With the insertion of the
Rows
and Columns
objects the code that first should work on lines and columns now results simpler, besides a lot of methods that before were in the grid now are in the RowInfoCollection
, RowInfo
, ColumnInfoCollection
or ColumnInfo
classes.
- The object
CellsContainer
is no more present, and even if logically was replaced from the panels, the more commons are linked directly to the grid and therefore the code that before used CellsContainer now could use directly the Grid
control.
- The old object
ICellModel
now is the object IDataModel
, while the object VisualProperties
now became IVisualModel
.
- The class CellControl for now is no more supported, I will think in future if introduce it again.
History
2.0.3.0 (25 March 2004)
- Moved and reviewed to the SourceLibrary project controls ComboBoxEx and TextBoxButton.
2.0.2.1 (24 March 2004)
- Fixed a bug on Range class. When adding or removing rows ColumnSpan and RowsSpan informations were not preserved.
2.0.2.0 (23 March 2004)
- Fixed a bug on ColumnHeader sort when used without FixedRows
2.0.1.0 (23 March 2004)
- Divided interface IDataModel and partially moved to SourceLibrary.ComponentModel.Validator.
- Renamed methods StringToObject to StringToValue and ObjectToString to ValueToString.
- Now to prevent editing the textbox of a ComboBox editor now you must use property AllowStringConversion = false. StandardValuesExclusive property allows to insert only the values present in the StandardValueList.
- Renamed method SupportStringConversion to IsStringConversionSupported().
- Removed methods ExportValue and ImportValue.
- EditorTextBox, EditorTextBoxButton e EditorComboBox now use TextBoxTyped control as textbox.
- Added editor EditorTextBoxNumeric for input char validation for numeric data type.
- AutoSize method for Header cell now add some extra space for sort icon.
- Added properties Grid.Columns[0].AutoSizeMode and Grid.Rows[0].AutoSizeMode for prevent autosize and stretch for specific columns/rows.
- Added properties Grid.Selection.SelectedRows and Grid.Selection.SelectedColumns that returns an array of selected rows or columns.
- Added methods OnEditStarting and OnEditEnded to the cell and to BehaviorModel, called when editing start and end.
- Renamed methods IDataModel.StartEdit to InternalStartEdit and EndEdit to InternalEndEdit because these are internal methods only, to start or end editing call Cell.StartEdit / Cell.EndEdit.
- Renamed method DataModel.GetDisplayString to DataModel.ValueToDisplayString.
- Added many examples for cell type and editors (See Sample 3).
- Fixed a bug in AutoSize when called with no rows or columns.
- Fixed a bug in SetFocusCell that don't put the focus in the grid.
- Fixed a bug for MouseDown when in editing mode.
2.0.0.0 (15 March 2004)
- First release of 2.0 version
License (BSD-style)
SourceGrid - .NET(C#) Grid control
Copyright (c) 2004, Davide Icardi
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
- Neither the name of the ORGANIZATION nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.