Introduction
LeerGridView is a replacement for the details view provided by .NET's built-in ListView, with the addition that the data in columns can be edited by the end user. So as not to reinvent the wheel, it is derived from Davide Icardi's beautiful SourceGrid control. The latest revision of that control can be found at his SourceGrid official website. LeerGridView was based on the 4.11 release of SourceGrid.
While the concept of an editable ListView is by no means new, I found myself using tabular lists over and over in my projects and was unsatisfied with the built-in ListView or any of the other available .NET ListView controls that I looked at. The .NET ListView is easy to use, but not very flexible. Simple features like the ability to change the color of the header columns are not provided, nor can you edit values in cells.
On the other hand, there are loads of commercial (i.e. expensive) ListView controls and some free ones as well. I tried a half-dozen or so and either did not like the features or found that using them was not as easy as I would have liked. Using a proven flexible grid control as a basis, I was able to capitalize on many features that have already been time-tested, such as using embedded DateTime pickers or other controls within the list's cells.
LeerGridView is really a work in progress. I built it for use in a project I am currently working on, but felt it to be useful enough to make it available to other programmers. I'm sure there are many features that could be added and that the underlying grid offers much of that code for free. However, my goal was more to start with something workable, maintainable and understandable. Features can be added later as needed.
You may notice that the namespace is LeerSoft.Tools
. That is because I have actually written a whole series of controls that I had made available through The Code Project and my website as well. The previous version released, however, was written for .NET 1.1 and will not work on .NET 2.0. My current version of LeerTools actually uses some 3rd party non-open-source controls, so it is not appropriate for distribution on The Code Project. I will, if there is any interest, make all my source code available through my website.
The LeerGridView downloadable project includes a basic *.chm help file.
Basic LeerGridView Concepts
Having used Microsoft's ListView for quite a while, I was happy with their concept of a list consisting of the following elements:
Column
: each Column
is assumed to have a single type of data, with an associated column heading.
Item
: although inappropriately named, an Item
represents a single row of data. The column heading row is not considered an item.
SubItem
: SubItem
s are simply the data for each column within a specific Item
(row).
Since the underlying grid is really just a collection of cells arranged in rows and columns, it was an easy leap to visualize a ListView that wraps the grid's functionality with the ease of use of a simple detailed list. As a starting point, I created two base classes: LeerItemBase
and LeerCollectionBase
.
LeerItemBase
LeerItemBase
is the base for a single
LeerGridColumn
,
LeerGridItem
or
LeerGridSubItem
. The base class simply provides some commonly used properties that each of the derived classes could use.
Parent
: this is the entity to which this object belongs. The Parent
of anything derived from LeerItemBase
is usually an object representing a collection of derived objects.
Selected
: this property is used to represent whether or not the object is selected. Even though some of the derived classes may not use the Selected
property, it is there for consistency. Methods in the parent's base class, LeerCollectionBase
, are available to locate selected indices and/or objects. For now, only one object in a collection of LeerBaseItem
should be selected.
Tag
: as customary, Tag
s are programmer-defined objects whose reference can be saved in another object. I always seem to find uses for tags, so I placed this property in the base class.
Index
: since each of the derived classes represents one object from within a collection, the common Index
property is automatically maintained to represent the object's relative position within its parent collection. This property is 0-based throughout LeerGridView.
LeerCollectionBase
LeerCollectionBase
is the base for a collection of LeerGridColumn
, LeerGridItem
or LeerGridSubItem
objects. The base class simply provides some commonly used properties and methods that each of the derived classes could use, such as adding/inserting/removing objects from the collection and searching for selected objects.
Grid controls aren't always the easiest to use in code and, as good as SourceGrid is, it is no exception. LeerGridView attempts to hide all the dirty work. At design time, you can create all the columns and the associated properties (such as the type of data in the column and the visual properties of color, font, etc.). LeerGridView will take care of initializing the grid to match the defined specifications. However, should the programmer decide that he really wants access to the underlying grid, the Grid
property is available to return its reference.
Keep in mind that the underlying grid's rows start at 0 and that the LeerGridView items (rows) will also start at 0. However, the first LeerGridItem
is actually the second grid row. To make this work, LeerGridView will handle the translation from item rows to grid rows behind the scene.
Using the Code
Once compiled, the LeerGridView.dll file should be added to your Visual Studio toolbox. LeerGridView will then be an available component to be placed on your forms. Also, be sure to reference the necessary DLLs from DevAge:
- DevAge.Core.dll
- DevAge.Windows.Forms.dll
- SourceGrid.dll
The most important properties to set would be the collection of Columns
, as well as the properties named Headerxxx
and Rowxxxx
, as they will set the default look and feel for the header and item rows. It is best to set the properties at design time, as I have not really thoroughly tested what would happen if you tried to add columns and change some basic properties after LeerGridView is already initialized. I suspect that you can change the layout as long as you call InitGridView
before loading the data rows.
Once the grid is established, you can do whatever is necessary to gather the data you wish to display. Then, when you are ready, you can populate the Items (data rows) at your convenience. Some principles to keep in mind are:
LeerGridItem
objects are most easily built by using the new
operator and supplying an array of objects to load into the LeerGridSubItem
objects attached to that Item
.
- The type of the objects assigned to the
LeerGridSubItem
objects should match the type of data that you have specified in the ColumnType
for each column. Failure to do that will likely result in exceptions thrown at run-time.
- The underlying
Grid
has cells that display data which will appear as strings. However, when the end user clicks on an editable column, a control for the type of column is constructed and used to edit the data. These editors expect that the objects in the cells are of the correct data type.
- It is probably faster to build an array of completely specified
LeerGridItem
s and then add them all at once using the LeerGridView.Items.AddRange()
method.
- To get the value contained within a row/column (remember, item row 0 is the 2nd
Grid
row), use code such as the code shown below. To get the top left data cell, assumed to be text, set nRowIndex
and nColIndex
to 0.
String str = (String)leerGridView1.Items[nRowIndex].SubItems[nColIndex].Value;
A sample of code to add a bunch of rows to a LeerGridView is shown below. LeerGridView was defined as having 5 columns of the following ColumnType
: text (read-only), ComboBox, DateTime, NumericUpDown and Time.
private void btnAdd500Rows_Click(object sender, EventArgs e)
{
LeerGridItem[] algi = new LeerGridItem[500];
LeerGridItem lgi;
for(int i = 0; i < 500; ++i)
{
lgi = new LeerGridItem(new Object[]
{
"Line " + n.ToString(), "Two", DateTime.Now, 7, DateTime.Now
});
algi[i] = lgi;
}
leerGridView1.Items.AddRange(algi);
}
Limitations and Other Items of Interest
Seeing as I wrote this control for my own purposes, it only has the features that I needed to make my applications work the way I wanted. I will certainly add features that can be implemented relatively easily when requests are made. With that in mind, please note the following limitations or behavioral issues that you may come across when using the control:
- Sorry, LeerGridView does not as yet support multiple selected rows.
- Horizontal scrolling is by column only, forcing the start of a column to appear at the left edge of the control. This is due to the horizontal scrolling behavior of the underlying
Grid
. In other words, horizontal scrolling may appear a bit jumpy. Because of this problem, LeerGridView deliberately limits the column width you can define to be less than the overall width provided for the control. If a column is wider than the control, the Grid
gets confused, so I try to avoid allowing that to happen.
- There are only a few events currently implemented. It should, however, be possible to hook into some of the events provided by the underlying
Grid
.
- LeerGridView is not optimized for resource (objects and memory) usage. In particular, being based on a grid, there is certainly overhead needed by the base class for every cell. In addition, the base class uses a view object for visual properties (color, etc.) of cells and allows these views to be reused. In LeerGridView, I will reuse the default view determined by the properties named
Rowxx
. However, if you change a specific property of an Item
or SubItem
, LeerGridView creates a custom view object for each involved cell based on the default row view.
- LeerGridView seems to have good performance with up to several thousand cells. I have not tested very large views. This is mostly because I am not a believer in presenting a UI to an end user that has an enormous amount of information crammed into a small control. This inevitably leads to tiny thumbs for scrolling and makes searching through large lists tedious. Of course, that is my opinion, for what it is worth.
- I tried to make the DesignMode look of LeerGridView to be responsive to changes made. I know improvements can be made in this area.
- The
LeerGridSubItem
class has a Text
property that may be redundant. It was eventually replaced with the Value
property, which makes more sense. It was not obvious to me in a cursory look how to get rid of that property, so I left it in. In general, I recommend using the Value
property when you want to Get
/Set
a cell's value.
History
Release 1.0; 2/20/2008