|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionI've been a member of CodeProject pretty much since its inception in one form or another and have been meaning to post an article for a while, this is a great site and I'm glad that I can finally give something back. I built the Superlist control whilst developing an RSS reader called FeedGhost. Although there are plenty of commercial grouped list controls available I wanted to have total control over the code and of course its usability. Superlist supports drag drop column customisation, grouping as well as handling thousands of entries smoothly. It's also highly customisable if you want to change its look and feel. In this article I'll explain how to use and extend the control in a demo project. If you download the source, you can find demo project under the Tests/SuperListTest directory. BackgroundBefore deciding to develop my own list control I spent a couple of weeks fighting the standard Listview, trying to get it to work the way I wanted, but I finally gave up when I couldn't get the selected items in the grouped visual order. We needed this in FeedGhost so that articles that the user multi-selected would be displayed in the same order in the corresponding HTML view. I decided to write the control from scratch rather than basing it for example on the Grid controls. In previous projects I've worked on, I've seen the grids bent and warped into doing the bidding of its creator only to be a maintenance millstone around the projects neck later; not quite working the way you want with plenty of patching code to get it *nearly* there. In the end you have a pile of brittle code that people are too scared to touch. I developed Superlist in two weeks, strangley enough it was about the same time I spent trying to get the Listview working in the first place, admittedly I spent the following two weeks fixing the bugs Using the CodeThe first point to note is I haven't done any forms designer compatibility work with this control. I tend to use the designer for laying the controls out and then go straight into the code to complete the rest of the work, hence no designer support for Superlist in terms of adding Columns and configuring them etc. To use the control you'll need of course to add it to a public SuperListTestForm()
{
InitializeComponent();
Column surnameColumn = new Column( "surname", "Surname", 120,
delegate( object item ) { return ((Person)item).Surname; } );
Column firstnameColumn = new Column( "firstname", "Firstname", 120,
delegate( object item ) { return ((Person)item).Firstname; } );
Column phoneColumn = new Column( "phone", "Phone", 100, delegate(
object item ) { return ((Person)item).Phone; } );
Column cityColumn = new Column( "city", "City", 60, delegate(
object item ) { return ((Person)item).City; } );
Column stateColumn = new Column( "state", "State", 70, delegate(
object item ) { return ((Person)item).State; } );
Column dateColumn = new Column( "date", "Date", 110, delegate(
object item ) { return ((Person)item).Date.ToString(); } );
dateColumn.GroupItemAccessor = new ColumnItemValueAccessor(
GroupValueFromItem );
dateColumn.MoveBehaviour = Column.MoveToGroupBehaviour.Copy;
dateColumn.GroupSortOrder = SortOrder.Descending;
surnameColumn.SortOrder = SortOrder.Ascending;
_superList.Columns.Add( firstnameColumn );
_superList.Columns.Add( phoneColumn );
_superList.Columns.Add( stateColumn );
_superList.Columns.Add( cityColumn );
_superList.Columns.Add( dateColumn );
_superList.Columns.GroupedItems.Add( dateColumn );
_superList.Columns.GroupedItems.Add( stateColumn );
_superList.SelectedItems.DataChanged +=
new SelectedItemsCollection.DataChangedHandler(
SelectedItems_DataChanged );
int tickStart = Environment.TickCount;
const int iterationCount = 1; // Change this if you want to increase
// the number of items in the list
for( int i = 0; i < iterationCount; i++ )
{
_superList.Items.AddRange( Person.GetData() );
}
}
Column ObjectThe column object is where most of your work lays in terms of getting the control up and running, you create it with the following constructor: public Column( string name, string caption, int width,
ColumnItemValueAccessor columnItemValueAccessor )
The public delegate object ColumnItemValueAccessor( object rowItem );
Once you've defined your columns you can add them to the list via the GroupingGrouping is as simple as adding the column to the SortingThe value returned by the BehaviourIn the past one of the performance bottelnecks that I've seen is where an application will add lots of items to a control causing it to visually slow down, as the control updates itself each time a new item is added. These problems are easy to fix and normally involve telling the control to disable rendering whilst the adding operation is in progress. We get around these potential problems with the Superlist as it processes changes to the list in the background, if you want the UI to syncronise with the changes straight away then you can call DesignEach visual aspect of the control like the header, rows and cells are all derived from
The CustomisingThe
When overriding a section the two main methods you'll be interested in will be #region Example of overriding rows
/// <summary />
/// Storage area for the row override.
/// </summary />
private RowOverrideExample _rowOverride;
private void toggleRowPaintingOverrideToolStripMenuItem_Click( object sender,
EventArgs e )
{
if( _rowOverride == null )
{
//
// Start overrride.
_rowOverride = new RowOverrideExample( _superList );
}
else
{
//
// Clear override.
_rowOverride.Dispose();
_rowOverride = null;
}
}
/// <summary />
/// Example of overriding rows giving a gradient fill look.
/// </summary />
private class RowOverrideExample: IDisposable
{
public RowOverrideExample(
BinaryComponents.SuperList.ListControl listControl )
{
_oldFactory = listControl.SectionFactory; // store old factory as we
// want to leave as we came.
_listControl = listControl;
//
// Replace the current SectionFactory with our override.
listControl.SectionFactory = new MySectionFactory(); //
_listControl.LayoutSections();
}
public void Dispose()
{
if( _oldFactory != null ) // put things back as they were
{
_listControl.SectionFactory = _oldFactory;
_listControl.LayoutSections();
}
}
private class MySectionFactory : SectionFactory
{
public override RowSection CreateRowSection(
BinaryComponents.SuperList.ListControl listControl,
RowIdentifier rowIdenifier,
HeaderSection headerSection,
int position )
{
return new MyRowSection( listControl, rowIdenifier,
headerSection, position );
}
}
private class MyRowSection : RowSection
{
public MyRowSection(
BinaryComponents.SuperList.ListControl listControl,
RowIdentifier rowIdentifier,
HeaderSection headerSection,
int position )
: base( listControl, rowIdentifier, headerSection, position )
{
_position = position;
}
public override void PaintBackground( Section.GraphicsSettings gs,
Rectangle clipRect )
{
Color from, to;
if( _position % 2 == 0 )
{
from = Color.White;
to = Color.LightBlue;
}
else
{
to = Color.White;
from = Color.LightBlue;
}
using( LinearGradientBrush lgb = new LinearGradientBrush(
this.Rectangle,
from,
to,
LinearGradientMode.Horizontal ) )
{
gs.Graphics.FillRectangle( lgb, this.Rectangle );
}
}
public override void Paint( Section.GraphicsSettings gs,
Rectangle clipRect )
{
base.Paint( gs, clipRect );
}
private int _position;
}
private BinaryComponents.SuperList.ListControl _listControl;
private SectionFactory _oldFactory;
}
#endregion
On the customisation You can also add your own ToolStripItems to it by overriding the Loading and Saving StateSuperlist's state can be saved and loaded with Saving Example using( System.IO.TextWriter textWriter = File.CreateText( ofd.FileName ) )
{
_superList.SerializeState( textWriter );
}
Loading Example
using( System.IO.TextReader textReader = File.OpenText( fileName ) )
{
_superList.DeSerializeState( textReader );
}
Wrapping it UpI hope you find this control useful and if you have any ideas, bugs or suggestions feel free leave a message here. I'll also be posting updates here as well as on my company site Binary Components.
|
||||||||||||||||||||||