[c#] DataGridView Sort method override

Pagina: 1
Acties:
  • 991 views sinds 30-01-2008
  • Reageer

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik maak gebruik van een aantal datagridview controls waar verschillende datatable objecten aan zijn gekoppeld. De datagridview control bevat geen mogelijkheid om een totaal waarde onderaan elke colom weer te geven. Daarom heb ik aan elke datatable zelf een rij toegevoegd met het totaal voor elke colom.

Dit werkt allemaal prima, echter als je tijdens runtime op de columnheader klikt sorteert de datagridview op basis van alle rijen; dus ook de totaalrij. Ik heb gezocht of er opties zijn op dit tegen te gaan, maar volgens mij is de enige optie om een custom classe te maken die van datagridview overerft en de sort method te overschrijven. De rijen moeten dan normaal gesorteerd worden, met als enige voorwaarde dat de huidige laatste rij altijd achteraan gesorteerd wordt.

Ik was niet helemaal zeker van welke method overload de datagridview control gebruik maakt. Volgens mij is het de tweede sort method. Hoe kan ik dit nagaan?

http://msdn2.microsoft.co...ms.datagridview.sort.aspx

Uitgaande van de tweede method heb ik het volgende opgesteld. Na wat nadenken en documentatie doorlopen heb ik echter nog geen idee hoe ik dit moet aanpakken. Misschien kunnen jullie me in de goede richting sturen.

C#:
1
2
3
4
5
6
7
    class CustomDataGridView : DataGridView
    {
        public override void Sort(DataGridViewColumn dataGridViewColumn, ListSortDirection direction)
        {
            
        }
    }

Acties:
  • 0 Henk 'm!

Verwijderd

Er zijn verschillende manieren om dit op te lossen. De Sort functie overriden lijkt mij niet de beste oplossing.

Beste oplossing lijkt mij SortCompare event van je DataGridView afvangen. Je krijgt daar een DataGridViewSortCompareEventArgs mee. Hierin heb je de cells die met elkaar vergeleken worden. Op de achtergrond loopt een loop die sorteert, en op basis van vergelijkingen van rijen met elkaar wordt de volgorde bepaald.

De properties CellValue1 en CellValue2 van DataGridViewSortCompareEventArgs geven de waarde van de cells aan, en RowIndex1 en RowIndex2 de rijnummers. Met die gegevens kun je aan de slag. Je moet zelf even bepalen op basis van RowIndex1 en RowIndex2 of je een rij hebt met de totaalwaarden.

Zo ja, dan geef je een SortResult (ook in de event arguments) en zet je Handled op true. SortResult is een getal met de volgende betekenis:

< 0: rij 1 moet eerder komen dan rij 2
= 0: rij 1 is gelijk aan rij 2
> 0: rij 1 moet later komen dan rij 2

Vaak worden -1, 0 en 1 gebruikt.

Als je geen rijen met totaal hebt, dan geef je gewoon return. Handled dus niet op true zetten. Er zal dan op de gewone manier gesorteerd worden.

Succes.

[ Voor 7% gewijzigd door Verwijderd op 15-12-2007 22:51 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik zal morgen eens kijken of dat een betere oplossing is, bedankt iig voor je input. Onderstaand is hoever ik ben gekomen met mijn huidige implementatie. Waar ik nog niet uit ben is of ik sort functionaliteit kan hergebruiken van .net. Het maken van een sorteer mechanisme voor integer waarden is bijvoorbeeld geen probleem, maar dit implementeren voor alle verschillende datatypen (b.v. string, DateTime, etc) is best veel werk. Het middelste stuk van onderstaande code is immers enkel het aanroepen van de standaard sort method van de datagridview. Daar moet ik nog even induiken.

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    class CustomDataGridView : DataGridView
    {
        public override void Sort(DataGridViewColumn dataGridViewColumn, ListSortDirection direction)
        {
            //Store the final row in a local variable and remove it from the collection.
            int rowCount = this.Rows.Count;
            DataGridViewRow lastRow = this.Rows[rowCount - 1];
            this.Rows.RemoveAt(rowCount - 1);

            //Sort the rows collection.
            if (direction == ListSortDirection.Ascending)
            {
                
            }
            else
            {

            }

            //Add the stored final row back to rows collection.
            this.Rows.Add(lastRow);
        }
    }

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 00:04
Wat negerzoen zegt. :)
Ik heb hier een gelijkaardig iets nodig gehad in een WinForms applicatie, en daar heb ik ook gewoon een IComparer gemaakt die, afhankelijk van de sorteervolgorde (aflopend of oplopend) gewoon het goede getal returned iedere keer de totaal-row vergeleken wordt.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
C#:
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
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            dataGridView1.ColumnCount = 4;

            string[] row1 = new string[]{"Meatloaf", 
                                        "Main Dish", "boringMeatloaf", "boringMeatloafRanking"};
            string[] row2 = new string[]{"Key Lime Pie", 
                                        "Dessert", "lime juice, evaporated milk", "****"};
            string[] row3 = new string[]{"Orange-Salsa Pork Chops", 
                                        "Main Dish", "pork chops, salsa, orange juice", "****"};
            string[] row4 = new string[]{"Black Bean and Rice Salad", 
                                        "Salad", "black beans, brown rice", "****"};
            string[] row5 = new string[]{"Chocolate Cheesecake", 
                                        "Dessert", "cream cheese", "***"};
            string[] row6 = new string[]{"Black Bean Dip", "Appetizer",
                                        "black beans, sour cream", "***"};
            object[] rows = new object[] { row1, row2, row3, row4, row5, row6 };

            foreach (string[] rowArray in rows)
            {
                dataGridView1.Rows.Add(rowArray);
            }

            this.dataGridView1.SortCompare += new System.Windows.Forms.DataGridViewSortCompareEventHandler(this.dataGridView_SortCompare);
        }

        private void dataGridView_SortCompare(object sender, DataGridViewSortCompareEventArgs e)
        {
            int rowCount = dataGridView1.Rows.Count;
            if (dataGridView1.AllowUserToAddRows == true)
                rowCount -= 1;
            
            //First row is final row: sort row 1 below row 2.
            if (e.RowIndex1 == rowCount - 1)
            {
                e.SortResult = 1;
                e.Handled = true;
            }
            //Second row is final row: sort row 2 below row 1.
            else if (e.RowIndex2 == rowCount - 1)
            {
                e.SortResult = - 1;
                e.Handled = true;
            }
        }
    }


Ik heb nu het bovenstaande. Als ik een rij één keer sorteer gaat het goed. Maar als ik dan nogmaals de gesorteerde colom sorteer (andersom dus), krijg ik de volgende exception.

Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index

Ik heb wat gedebugged en ik krijg de exception enkel nadat de eventhandler gedraaid heeft en row 0 en 5 zijn vergeleken. Het gekke (?) is dat bij de eerste keer sorteren row 0 en 5 nooit worden vergeleken. Je kan bovenstaande code zelf compileren door een datagridview1 aan je form toe te voegen.

Acties:
  • 0 Henk 'm!

Verwijderd

Je gebruikt de event arguments in ieder geval goed. Je maakt alleen een veelgemaakte fout: je moet in SortCompare zélf rekening houden met ascending of descending sorteren. Gelukkig wel, want anders zou .NET alsnog je totalenkolom bovenaan plaatsen bij descending.

Dus:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
        private void dataGridView_SortCompare(object sender, DataGridViewSortCompareEventArgs e)
        {
            int rowCount = dataGridView1.Rows.Count;
            if (dataGridView1.AllowUserToAddRows == true)
                rowCount -= 1;

            //First row is final row: sort row 1 below row 2. 
            if (e.RowIndex1 == rowCount - 1)
            {
                e.SortResult = 1;
                e.Handled = true;
            }
            //Second row is final row: sort row 2 below row 1. 
            else if (e.RowIndex2 == rowCount - 1)
            {
                e.SortResult = -1;
                e.Handled = true;
            }

            if (e.Handled && dataGridView1.SortOrder == SortOrder.Descending)
                e.SortResult = -e.SortResult;
        }


Getest en werkt 8)

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Heel erg bedankt, dat klinkt inderdaad logisch. (De exception is echter wel een beetje wazig?) Ik loop alleen tegen het volgende probleem aan bij het implementeren van deze oplossing in mijn project.

Van MSDN:

This event occurs only when the DataSource property is not set and the VirtualMode property value is false.

Mijn grids zijn echter wel databound. Al het werk voor niks of is er een makkelijke manier om dit op te lossen?

[ Voor 5% gewijzigd door Verwijderd op 16-12-2007 20:00 ]

Pagina: 1