Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

LeerGridView: an Editable ListView

0.00/5 (No votes)
27 Feb 2008 1  
An easy-to-use ListView with editable fields derived from a powerful grid control

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: SubItems 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, Tags 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 LeerGridItems 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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here