Toon posts:

C# listView sorting

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Hi,

Ik wil in een listView een selectie sorteren. Deze code moet de basis worden voor het selecteren op basis van meerdere kolommen, maar uiteraard moet ik eerst een single kolom werkend zien te krijgen :

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        private void btnSort_Click(object sender, EventArgs e)
        {
            if (listView1.SelectedItems.Count == 0)
            {
                return;
            }

            for (int i = 0; i < listView1.Items.Count; i++)
            {
                if (listView1.Items[i].Selected && listView1.Items[i+1].Selected)
                {
                    if (string.Compare(listView1.Items[i].SubItems[0].Text, listView1.Items[i + 1].SubItems[0].Text) > 0)
                    {
                        ListViewItem lvItem = (ListViewItem)listView1.Items[i].Clone();
                        listView1.Items.Remove(listView1.Items[i]);
                        listView1.Items.Insert(i+1, lvItem);
                    }
                }
            }
        }

Selecteer ik twee aaneengesloten items die verkeerdom staan, worden deze netjes omgedraaid. Is het een grotere selectie die niet klopt dan gebeurt er wel iets, maar totaal niet wat ik verwacht.

Ik zal uiteraard iets over het hoofd zien :)

Acties:
  • 0 Henk 'm!

  • Daos
  • Registratie: Oktober 2004
  • Niet online
- In plaats van zelf sorteren kan je ook Sort van een List<> of OrderBy van LINQ gebruiken. Dat werkt altijd en is nog vrij snel ook.
- listView1.Items.Insert doet het bij mij niet. Ookal geef ik een index mee, alles komt achteraan. Ik moet eerst de lijst leeghalen en dan alles met Add weer invoegen.

Mijn algoritme ziet er zo uit:
- bool ophalen of je oplopend of aflopend wilt sorteren
- alle items ophalen en in List<ListViewItem> zetten
- hieruit geselecteerde items halen
- hieruit geselecteerde indices halen
- lijst geselecteerde items sorteren met eigen IComparer<ListViewItem>
- indien aflopend deze lijst omdraaien
- listview leeghalen
- listview opnieuw vullen uit alle items, maar als een index in de geselecteerde indices voorkomt dan een gesorteerd item pakken

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:57
Een ListView control heeft een method Sort die je kunt gebruiken.

Je kan aan de ListViewItemSorter property van de ListView een object assignen die de IComparer interface implementeert.
Zo doe ik het nl. altijd. De class die je maakt, kan dan ook bijhouden welke kolom er gesorteerd wordt, en zo kan je er ook makkelijk voor zorgen dat als je nogmaals op dezelfde columnheader klikt, die kolom in omgekeerde volgorde gesorteerd wordt.

Ik heb een base class gemaakt die er als volgt uit ziet

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
 public abstract class ListViewItemSorter : IComparer, IComparer<ListViewItem>
    {
        private int                     _columnToSort;
        
        public int                      ColumnToSort
        {
            get
            {
                return _columnToSort;
            }
            set
            {
                if( _columnToSort == value )
                {
                    if( SortOrder == SortOrder.Ascending )
                    {
                        SortOrder = SortOrder.Descending;
                    }
                    else
                    {
                        SortOrder = SortOrder.Ascending;
                    }
                }
                else
                {
                    _columnToSort = value;
                    SortOrder = SortOrder.Ascending;
                }
            }            
        }

        public SortOrder                SortOrder
        {
            get;
            set;
        }

        protected ListViewItemSorter()
        {
            SortOrder = SortOrder.None;
        }

        public int Compare( object x, object y )
        {
            ListViewItem leftListViewItem = x as ListViewItem;
            ListViewItem rightListViewItem = y as ListViewItem;

            if( leftListViewItem == null )
            {
                throw new ArgumentException ("An instance of object ListViewItem expected.", "x");
            }

            if( rightListViewItem == null )
            {
                throw new ArgumentException ("An instance of object ListViewItem expected.", "y");
            }

            return this.Compare (leftListViewItem, rightListViewItem);
        }

        public int Compare( ListViewItem x, ListViewItem y )
        {
            int result = this.CompareListViewItems (x, y);

            // The result must be inverted, if we have to sort in descending fashion.
            if( SortOrder == SortOrder.Descending )
            {
                result *= -1;
            }

            return result;
        }

        protected abstract int CompareListViewItems( ListViewItem left, ListViewItem right );

    }


Daar kan je voor iedere specifieke ListView die je hebt een class van overerven. je hoeft dan enkel de abstracte CompareListViewItems method te implementeren, en de juiste sortering per column te gaan implementeren. (Afhankelijk van het gegeven dat je in iedere kolom toont).

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • FeronIT
  • Registratie: Mei 2015
  • Laatst online: 09-10 21:00
Zonder een volledig sorteer algoritme voor te kauwen (voorbeelden genoeg en zoals gezegd ondersteunt het .net framework je hierin ook), vergelijkt je in jou algoritme iedere waarde met de volgende en wissel je ze om indien de volgorde verkeerd is. Een item kan dus hooguit 1 plek achteruit gaan, vooruit kan wel vaker doordat het opschuift met de index. Als je dit algoritme zo vaak uitvoert dat de lijst niet meer wijzigt werkt het wel, maar is niet er efficient

Acties:
  • 0 Henk 'm!

  • Daos
  • Registratie: Oktober 2004
  • Niet online
Het algoritme dat je dan krijgt heet bubblesort en is inderdaad een van de slechtere.

Acties:
  • 0 Henk 'm!

  • Camulos
  • Registratie: Januari 2009
  • Laatst online: 07-10 12:42

Camulos

Stampert

Daos schreef op zaterdag 07 november 2015 @ 20:53:
- In plaats van zelf sorteren kan je ook Sort van een List<> of OrderBy van LINQ gebruiken. Dat werkt altijd en is nog vrij snel ook.
^^ dit is de meest elegante antwoord. Begrijpbare code, met standaard implementatie (eventueel met een iComparer implementatie voor generics).

Als je serieus zelf wilt gaan sorteren, check dan eens deze visualisatie van de verschillende soorten die er zijn: http://www.sorting-algorithms.com/

Not just an innocent bystander

Pagina: 1