Guest post: response from Regis on DGV questions

Hi jfo,
I downloaded the samples and the FAQ document. This grid is really cool. Thank you very much.

I also have some questions for you.

Question 1: First, does the DataGridView allow ordering by multiple columns? For example, if I want to order columns first by Name, then by City, then by Locality etc, can I do that with DataGridView?

Question 2: Second, does it allow grouping of columns? I've seen this in the Infragistics grid, wherein you drag a column to an area above it and the view changes to a list collapsible rows, and each row has the grouped column name and the group item as its caption. Is this possible?

Question 3: Third, I saw some comments at this link that say the DataGridView is very slow. Could you please share your thoughts on this? Here is the link:
https://weblogs.asp.net/fbouma/archive/2005/10/29/428848.aspx

We are in the process of evaluating different options for our project, and your inputs would help us a lot.

Thanks and Regards,
Girish

________________________________________
From: Regis Brid
To: Jessica Fosler
Subject: RE: DataGridView FAQ posted

Answer to Question 1

First, does the DataGridView allow ordering by multiple columns? For example, if I want to order columns first by Name, then by City, then by Locality etc, can I do that with DataGridView?

The answer to this can be found in the FAQ
https://www.windowsforms.net/Samples/Go%20To%20Market/DataGridView/DataGridView%20FAQ.doc#_Toc119903499:

How do I sort on multiple columns?
By default the DataGridView control does not provide sorting on multiple columns. Depending upon if the DataGridView is databound or not, you can provide additional support for sorting on multiple columns.

9.1 Databound DataGridView
When the DataGridView is databound the datasource can be sorted on multiple columns and the DataGridView will respect that sorting, but the only the first sorted column will display the sort glyph. In addition, the SortedColumn property will only return the first sorted column.

Some datasources have built in support for sorting on multiple columns. If your datasource implements IBindingListView and provides support for the Sort property, then using it will provide support for multi-column sorting. To indicate in the grid that multiple columns are sorted on, manually set a column’s SortGlyphDirection to properly indicate that the column is sorted.

The following example uses a DataTable and sets the default view’s Sort property to sort on the second and third columns. The example also demonstrates setting the column’s SortGlyphDirection. The example assumes that you have a DataGridView and a BindingSource component on your form:

DataTable dt = new DataTable();
dt.Columns.Add("C1", typeof(int));
dt.Columns.Add("C2", typeof(string));
dt.Columns.Add("C3", typeof(string));

dt.Rows.Add(1, "1", "Test1");
dt.Rows.Add(2, "2", "Test2");
dt.Rows.Add(2, "2", "Test1");
dt.Rows.Add(3, "3", "Test3");
dt.Rows.Add(4, "4", "Test4");
dt.Rows.Add(4, "4", "Test3");

DataView view = dt.DefaultView;
view.Sort = "C2 ASC, C3 ASC";
bindingSource.DataSource = view;

DataGridViewTextBoxColumn col0 = new DataGridViewTextBoxColumn();
col0.DataPropertyName = "C1";
dataGridView1.Columns.Add(col0);
col0.SortMode = DataGridViewColumnSortMode.Programmatic;
col0.HeaderCell.SortGlyphDirection = SortOrder.None;

DataGridViewTextBoxColumn col1 = new DataGridViewTextBoxColumn();
col1.DataPropertyName = "C2";
dataGridView1.Columns.Add(col1);
col1.SortMode = DataGridViewColumnSortMode.Programmatic;
col1.HeaderCell.SortGlyphDirection = SortOrder.Ascending;

DataGridViewTextBoxColumn col2 = new DataGridViewTextBoxColumn();
col2.DataPropertyName = "C3";
dataGridView1.Columns.Add(col2);
col2.SortMode = DataGridViewColumnSortMode.Programmatic;
col2.HeaderCell.SortGlyphDirection = SortOrder.Ascending;

9.2 Unbound DataGridView
To provide support for sorting on multiple columns you can handle the SortCompare event or call the Sort(IComparer) overload of the Sort method for greater sorting flexibility.

9.2.1 Custom Sorting Using the SortCompare Event
The following code example demonstrates custom sorting using a SortCompare event handler. The selected DataGridViewColumn is sorted and, if there are duplicate values in the column, the ID column is used to determine the final order.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

class Form1 : Form
{
private DataGridView dataGridView1 = new DataGridView();

    // Establish the main entry point for the application.
[STAThreadAttribute()]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}

    public Form1()
{
// Initialize the form.
// This code can be replaced with designer generated code.
dataGridView1.AllowUserToAddRows = false;
dataGridView1.Dock = DockStyle.Fill;
dataGridView1.SortCompare += new DataGridViewSortCompareEventHandler(
this.dataGridView1_SortCompare);
Controls.Add(this.dataGridView1);
this.Text = "DataGridView.SortCompare demo";

        PopulateDataGridView();
}

    // Replace this with your own population code.
public void PopulateDataGridView()
{
// Add columns to the DataGridView.
dataGridView1.ColumnCount = 3;

        // Set the properties of the DataGridView columns.
dataGridView1.Columns[0].Name = "ID";
dataGridView1.Columns[1].Name = "Name";
dataGridView1.Columns[2].Name = "City";
dataGridView1.Columns["ID"].HeaderText = "ID";
dataGridView1.Columns["Name"].HeaderText = "Name";
dataGridView1.Columns["City"].HeaderText = "City";

        // Add rows of data to the DataGridView.
dataGridView1.Rows.Add(new string[] { "1", "Parker", "Seattle" });
dataGridView1.Rows.Add(new string[] { "2", "Parker", "New York" });
dataGridView1.Rows.Add(new string[] { "3", "Watson", "Seattle" });
dataGridView1.Rows.Add(new string[] { "4", "Jameson", "New Jersey" });
dataGridView1.Rows.Add(new string[] { "5", "Brock", "New York" });
dataGridView1.Rows.Add(new string[] { "6", "Conner", "Portland" });

        // Autosize the columns.
dataGridView1.AutoResizeColumns();
}

    private void dataGridView1_SortCompare(object sender,
DataGridViewSortCompareEventArgs e)
{
// Try to sort based on the cells in the current column.
e.SortResult = System.String.Compare(
e.CellValue1.ToString(), e.CellValue2.ToString());

        // If the cells are equal, sort based on the ID column.
if (e.SortResult == 0 && e.Column.Name != "ID")
{
e.SortResult = System.String.Compare(
dataGridView1.Rows[e.RowIndex1].Cells["ID"].Value.ToString(),
dataGridView1.Rows[e.RowIndex2].Cells["ID"].Value.ToString());
}
e.Handled = true;
}
}

9.2.2 Custom Sorting Using the IComparer Interface
The following code example demonstrates custom sorting using the Sort(IComparer) overload of the Sort method, which takes an implementation of the IComparer interface to perform a multiple-column sort.

using System;
using System.Drawing;
using System.Windows.Forms;

class Form1 : Form
{
private DataGridView DataGridView1 = new DataGridView();
private FlowLayoutPanel FlowLayoutPanel1 = new FlowLayoutPanel();
private Button Button1 = new Button();
private RadioButton RadioButton1 = new RadioButton();
private RadioButton RadioButton2 = new RadioButton();

    // Establish the main entry point for the application.
[STAThreadAttribute()]
public static void Main()
{
Application.Run(new Form1());
}

    public Form1()
{
// Initialize the form.
// This code can be replaced with designer generated code.
AutoSize = true;
Text = "DataGridView IComparer sort demo";

        FlowLayoutPanel1.FlowDirection = FlowDirection.TopDown;
FlowLayoutPanel1.Location = new System.Drawing.Point(304, 0);
FlowLayoutPanel1.AutoSize = true;

        FlowLayoutPanel1.Controls.Add(RadioButton1);
FlowLayoutPanel1.Controls.Add(RadioButton2);
FlowLayoutPanel1.Controls.Add(Button1);

        Button1.Text = "Sort";
RadioButton1.Text = "Ascending";
RadioButton2.Text = "Descending";
RadioButton1.Checked = true;

        Controls.Add(FlowLayoutPanel1);
Controls.Add(DataGridView1);
}

    protected override void OnLoad(EventArgs e)
{
PopulateDataGridView();
Button1.Click += new EventHandler(Button1_Click);

        base.OnLoad(e);
}

    // Replace this with your own code to populate the DataGridView.
private void PopulateDataGridView()
{

        DataGridView1.Size = new Size(300, 300);

        // Add columns to the DataGridView.
DataGridView1.ColumnCount = 2;

        // Set the properties of the DataGridView columns.
DataGridView1.Columns[0].Name = "First";
DataGridView1.Columns[1].Name = "Last";
DataGridView1.Columns["First"].HeaderText = "First Name";
DataGridView1.Columns["Last"].HeaderText = "Last Name";
DataGridView1.Columns["First"].SortMode =
DataGridViewColumnSortMode.Programmatic;
DataGridView1.Columns["Last"].SortMode =
DataGridViewColumnSortMode.Programmatic;

        // Add rows of data to the DataGridView.
DataGridView1.Rows.Add(new string[] { "Peter", "Parker" });
DataGridView1.Rows.Add(new string[] { "James", "Jameson" });
DataGridView1.Rows.Add(new string[] { "May", "Parker" });
DataGridView1.Rows.Add(new string[] { "Mary", "Watson" });
DataGridView1.Rows.Add(new string[] { "Eddie", "Brock" });
}

    private void Button1_Click(object sender, EventArgs e)
{
if (RadioButton1.Checked == true)
{
DataGridView1.Sort(new RowComparer(SortOrder.Ascending));
}
else if (RadioButton2.Checked == true)
{
DataGridView1.Sort(new RowComparer(SortOrder.Descending));
}
}

    private class RowComparer : System.Collections.IComparer
{
private static int sortOrderModifier = 1;

        public RowComparer(SortOrder sortOrder)
{
if (sortOrder == SortOrder.Descending)
{
sortOrderModifier = -1;
}
else if (sortOrder == SortOrder.Ascending)
{
sortOrderModifier = 1;
}
}

        public int Compare(object x, object y)
{
DataGridViewRow DataGridViewRow1 = (DataGridViewRow)x;
DataGridViewRow DataGridViewRow2 = (DataGridViewRow)y;

            // Try to sort based on the Last Name column.
int CompareResult = System.String.Compare(
DataGridViewRow1.Cells[1].Value.ToString(),
DataGridViewRow2.Cells[1].Value.ToString());

            // If the Last Names are equal, sort based on the First Name.
if (CompareResult == 0)
{
CompareResult = System.String.Compare(
DataGridViewRow1.Cells[0].Value.ToString(),
DataGridViewRow2.Cells[0].Value.ToString());
}
return CompareResult * sortOrderModifier;
}
}
}

Answer to Question 2

Second, does it allow grouping of columns? I've seen this in the Infragistics grid, wherein you drag a column to an area above it and the view changes to a list collapsible rows, and each row has the grouped column name and the group item as its caption. Is this possible?

This is not a built-in feature but can be achieved via customization. There may be a sample under https://www.windowsforms.net/WhidbeyFeatures/default.aspx?PageID=2&ItemID=13&Cat=Controls&tabindex=5
At least it shows how to do custom row painting which is required here.

Answer to Question 3

Third, I saw some comments at this link that say the DataGridView is very slow. Could you please share your thoughts on this? Here is the link:
https://weblogs.asp.net/fbouma/archive/2005/10/29/428848.aspx

We improved the performance by 30% since Beta2. Using the techniques from https://www.windowsforms.net/Samples/Go%20To%20Market/DataGridView/DataGridView%20FAQ.doc#_Toc119903483 will help with performance. 

If you have a particular scenario you would like us to look at, please send us a repro project to https://lab.msdn.microsoft.com/productfeedback/ so we can take a look at profiling what is going on.