Click here to Skip to main content
Click here to Skip to main content

A Much Easier to Use ListView

By , 29 Oct 2012
 
ObjectListView-2_2.zip
ObjectListView-2.2
COPYING
ObjectListView
bin
Release
ObjectListView.dll
ObjectListView.FxCop
ObjectListView.shfb
Properties
objectlistview.zip
ObjectListView
ObjectListView
COPYING
ObjectListView
bin
Debug
ObjectListView.FxCop
ObjectListView.shfb
Properties
ObjectListView20.zip
ObjectListView.FxCop
ObjectListView.shfb
Properties
ObjectListViewDemo.zip
ObjectListViewDemo
Demo
Properties
COPYING
AnimatedGifs
3dlink1.gif
cd1.gif
circum.gif
cool3.gif
enter3.gif
envelope.gif
exclame.gif
eye2.gif
net2.gif
new5.gif
Photos
ak.png
cp.png
cr.png
es.png
gab.png
gp.png
jp.png
jr.png
mb.png
ns.png
sj.png
sp.png
Resources
down16.png
Espresso Maker.ico
folder16.png
movie16.png
music16.png
star16.png
tick16.png
ListViewPrinter.dll
ObjectListView.dll
ObjectListViewDemo20.zip
COPYING
Demo
AnimatedGifs
3dlink1.gif
cd1.gif
circum.gif
cool3.gif
enter3.gif
envelope.gif
exclame.gif
eye2.gif
net2.gif
new5.gif
Photos
ak.png
cp.png
cr.png
es.png
gab.png
gp.png
jp.png
jr.png
mb.png
ns.png
sj.png
sp.png
Resources
down16.png
Espresso Maker.ico
folder16.png
movie16.png
music16.png
star16.png
tick16.png
ListViewPrinter
Properties
ListViewPrinterDemo
Properties
Settings.settings
Resources
compass16.png
ObjectListView.FxCop
ObjectListView.shfb
Properties
Tests
OLVTests.nunit
ObjectListViewDll20.zip
ObjectListView.dll
ObjectListViewFull-2_2.zip
COPYING
3dlink1.gif
cd1.gif
circum.gif
cool3.gif
enter3.gif
envelope.gif
exclame.gif
eye2.gif
net2.gif
new5.gif
ak.png
cp.png
cr.png
es.png
gab.png
gp.png
jp.png
jr.png
mb.png
ns.png
sj.png
sp.png
Properties
down16.png
Espresso Maker.ico
folder16.png
limeleaf.png
movie16.png
music16.png
redback1.png
redbull.png
star16.png
tick16.png
docs
blog.rst
blog1.rst
blog2.rst
cellEditing.rst
changelog.rst
ClassDiagram.dia
ClassDiagram-VirtualList.dia
download.rst
dragdrop.rst
faq.rst
features.rst
gettingStarted.rst
images
ClassDiagram.png
ClassDiagram-VirtualList.png
index.rst
listCtrlPrinter.rst
majorClasses.rst
overlays.rst
ownerDraw.rst
recipes.rst
whatsnew.rst
Settings.settings
compass16.png
bin
Release
ObjectListView.FxCop
ObjectListView.shfb
OLVTests.nunit
ObjectListViewFull.zip
ObjectListViewFull
Demo
obj
Debug
TempPE
Properties
ListViewPrinter
bin
Debug
obj
Debug
TempPE
ListViewPrinterDemo
bin
Debug
obj
Debug
TempPE
ObjectListView
bin
Debug
obj
Debug
TempPE
Tests
bin
Debug
obj
Debug
TempPE
COPYING
AnimatedGifs
3dlink1.gif
cd1.gif
circum.gif
cool3.gif
enter3.gif
envelope.gif
exclame.gif
eye2.gif
net2.gif
new5.gif
Photos
ak.png
cp.png
cr.png
es.png
gab.png
gp.png
jp.png
jr.png
mb.png
ns.png
sj.png
sp.png
Resources
down16.png
Espresso Maker.ico
folder16.png
movie16.png
music16.png
star16.png
tick16.png
docs
cellEditing.rst
changelog.rst
ClassDiagram.dia
ClassDiagram-VirtualList.dia
faq.rst
features.rst
gettingStarted.rst
index.rst
listCtrlPrinter.rst
majorClasses.rst
ownerDraw.rst
recipes.rst
whatsnew.rst
Properties
Properties
Settings.settings
Resources
compass16.png
ObjectListView.FxCop
ObjectListView.shfb
Properties
OLVTests.nunit
/*
 * Comparers - Various Comparer classes used within ObjectListView
 *
 * Author: Phillip Piper
 * Date: 25/11/2008 17:15 
 *
 * Change log:
 * 2008-12-20  JPP  - Fixed bug with group comparisons when a group key was null (SF#2445761)
 * 2008-11-25  JPP  Initial version
 *
 * TO DO:
 *
 * Copyright (C) 2006-2008 Phillip Piper
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
 */

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;

namespace BrightIdeasSoftware
{
    /// <summary>
    /// ColumnComparer is the workhorse for all comparison between two values of a particular column.
    /// If the column has a specific comparer, use that to compare the values. Otherwise, do
    /// a case insensitive string compare of the string representations of the values.
    /// </summary>
    /// <remarks><para>This class inherits from both IComparer and its generic counterpart
    /// so that it can be used on untyped and typed collections.</para></remarks>
    public class ColumnComparer : IComparer, IComparer<OLVListItem>
    {
        public ColumnComparer(OLVColumn col, SortOrder order)
        {
            this.column = col;
            this.sortOrder = order;
        }

        public ColumnComparer(OLVColumn col, SortOrder order, OLVColumn col2, SortOrder order2)
            : this(col, order)
        {
            // There is no point in secondary sorting on the same column
            if (col != col2)
                this.secondComparer = new ColumnComparer(col2, order2);
        }

        public int Compare(object x, object y)
        {
            return this.Compare((OLVListItem)x, (OLVListItem)y);
        }

        public int Compare(OLVListItem x, OLVListItem y)
        {
            int result = 0;
            object x1 = this.column.GetValue(x.RowObject);
            object y1 = this.column.GetValue(y.RowObject);

            if (this.sortOrder == SortOrder.None)
                return 0;

            // Handle nulls. Null values come last
            bool xIsNull = (x1 == null || x1 == System.DBNull.Value);
            bool yIsNull = (y1 == null || y1 == System.DBNull.Value);
            if (xIsNull || yIsNull) {
                if (xIsNull && yIsNull)
                    result = 0;
                else
                    result = (xIsNull ? -1 : 1);
            } else {
                result = this.CompareValues(x1, y1);
            }

            if (this.sortOrder == SortOrder.Descending)
                result = 0 - result;

            // If the result was equality, use the secondary comparer to resolve it
            if (result == 0 && this.secondComparer != null)
                result = this.secondComparer.Compare(x, y);

            return result;
        }

        public int CompareValues(object x, object y)
        {
            // Force case insensitive compares on strings
            String xAsString = x as String;
            if (xAsString != null)
                return String.Compare(xAsString, (String)y, StringComparison.CurrentCultureIgnoreCase);
            else {
                IComparable comparable = x as IComparable;
                if (comparable != null)
                    return comparable.CompareTo(y);
                else
                    return 0;
            }
        }

        private OLVColumn column;
        private SortOrder sortOrder;
        private ColumnComparer secondComparer;
    }

    /// <summary>
    /// This comparer sort list view groups.
    /// It does this on the basis of the values in the Tags, if we can figure out how to compare
    /// objects of that type. Failing that, it uses a case insensitive compare on the group header.
    /// </summary>
    public class ListViewGroupComparer : IComparer<ListViewGroup>
    {
        public ListViewGroupComparer(SortOrder order)
        {
            this.sortOrder = order;
        }

        public int Compare(ListViewGroup x, ListViewGroup y)
        {
            // If we know how to compare the tags, do that.
            // Otherwise do a case insensitive compare on the group header.
            // We have explicitly catch the "almost-null" value of DBNull.Value,
            // since comparing to that value always produces a type exception.
            int result;
            IComparable comparable = x.Tag as IComparable;
            if (comparable != null && y.Tag != null && y.Tag != System.DBNull.Value)
                result = comparable.CompareTo(y.Tag);
            else
                result = String.Compare(x.Header, y.Header, StringComparison.CurrentCultureIgnoreCase);

            if (this.sortOrder == SortOrder.Descending)
                result = 0 - result;

            return result;
        }

        private SortOrder sortOrder;
    }

    /// <summary>
    /// This comparer can be used to sort a collection of model objects by a given column
    /// </summary>
    public class ModelObjectComparer : IComparer
    {
        public ModelObjectComparer(OLVColumn col, SortOrder order)
        {
            this.column = col;
            this.sortOrder = order;
        }

        public ModelObjectComparer(OLVColumn col, SortOrder order, OLVColumn col2, SortOrder order2)
            : this(col, order)
        {
            // There is no point in secondary sorting on the same column
            if (col != col2)
                this.secondComparer = new ModelObjectComparer(col2, order2);
        }

        public int Compare(object x, object y)
        {
            int result = 0;
            object x1 = this.column.GetValue(x);
            object y1 = this.column.GetValue(y);

            if (this.sortOrder == SortOrder.None)
                return 0;

            // Handle nulls. Null values come last
            bool xIsNull = (x1 == null || x1 == System.DBNull.Value);
            bool yIsNull = (y1 == null || y1 == System.DBNull.Value);
            if (xIsNull || yIsNull) {
                if (xIsNull && yIsNull)
                    result = 0;
                else
                    result = (xIsNull ? -1 : 1);
            } else {
                result = this.CompareValues(x1, y1);
            }

            if (this.sortOrder == SortOrder.Descending)
                result = 0 - result;

            // If the result was equality, use the secondary comparer to resolve it
            if (result == 0 && this.secondComparer != null)
                result = this.secondComparer.Compare(x, y);

            return result;
        }

        public int CompareValues(object x, object y)
        {
            // Force case insensitive compares on strings
            String xStr = x as String;
            if (xStr != null)
                return String.Compare(xStr, (String)y, StringComparison.CurrentCultureIgnoreCase);
            else {
                IComparable comparable = x as IComparable;
                if (comparable != null)
                    return comparable.CompareTo(y);
                else
                    return 0;
            }
        }

        private OLVColumn column;
        private SortOrder sortOrder;
        private ModelObjectComparer secondComparer;
    }

}

By viewing downloads associated with this article you agree to the Terms of use and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

About the Author

Phillip Piper
Team Leader
Australia Australia
Member
Phillip has been playing with computers since the Apple II was the hottest home computer available. He learned the fine art of C programming and Guru meditation on the Amiga.
 
C# and Python are his languages of choice. Smalltalk is his mentor for simplicity and beauty. C++ is to programming what drills are to visits to the dentist.
 
He worked for longer than he cares to remember as Lead Programmer and System Architect of the Objective document management system. (www.objective.com)
 
He has lived for 10 years in northern Mozambique, teaching in villages.
 
He is currently developing high volume trading software for an Australian trading house.

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 30 Oct 2012
Article Copyright 2006 by Phillip Piper
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid