Windows Forms DataGridViewを使用して、MyObject
オブジェクトの一般的なリストを表示しています。
まず、このコレクションをBindingSource
コレクションにラップし、次に:
dataGridView.DataSource = myBindingSource;
私がやりたいのは、ユーザーがMyObjectの具体的なプロパティを表す列のヘッダーをクリックして列を並べ替えることを許可することです。
バインドする前に並べ替えを行う必要がある記事をいくつか読みました。しかし、列がすでにバインドされているときに言われるので、列をリアルタイムで並べ替えたい場合は役に立ちません。
問題は、正確に何をする必要があるのかということです。つまり、DataGridViewで並べ替え矢印が表示されますおよびすべての列を並べ替えることができます?
私の解決策はこれです:
私はmyBindingSourceを自分で操作し、別のスレッドで並べ替え、グループ化を行います。次に、単純に結果をDataGridViewにバインドします。
myDataGridView.DataSource = bindingSource;
この目的のために、すべての列をソートするように設定しました'Programatically'
(デザイナー)次に、設定して手動で矢印(ASCENDING/DESCENDING)を追加します
cell.SortGlyphDirection = ... ;
コードビハインドで。
データソースがジェネリックリストであるdatagridviewの列をソートするための完全なコード
//-----------------------------------------------------------------------------------------
//In the form - In constructor or form load, populate the grid.
//--------------------------------------------------------------------------------------------
List<student> students;
private void PopulateList()
{
student std1 = new student("sss", 15, "Female");
student std2 = new student("ddd", 12, "Male");
student std3 = new student("zzz", 16, "Male");
student std4 = new student("qqq", 14, "Female");
student std5 = new student("aaa", 11, "Male");
student std6 = new student("lll", 13, "Female");
students = new List<student>();
students.Add(std1);
students.Add(std2);
students.Add(std3);
students.Add(std4);
students.Add(std5);
students.Add(std6);
dataGridView1.DataSource = students;
}
//---------------------------------------------------------------------------------------------
//Comparer class to perform sorting based on column name and sort order
//---------------------------------------------------------------------------------------------
class StudentComparer : IComparer<Student>
{
string memberName = string.Empty; // specifies the member name to be sorted
SortOrder sortOrder = SortOrder.None; // Specifies the SortOrder.
/// <summary>
/// constructor to set the sort column and sort order.
/// </summary>
/// <param name="strMemberName"></param>
/// <param name="sortingOrder"></param>
public StudentComparer(string strMemberName, SortOrder sortingOrder)
{
memberName = strMemberName;
sortOrder = sortingOrder;
}
/// <summary>
/// Compares two Students based on member name and sort order
/// and return the result.
/// </summary>
/// <param name="Student1"></param>
/// <param name="Student2"></param>
/// <returns></returns>
public int Compare(Student Student1, Student Student2)
{
int returnValue = 1;
switch (memberName)
{
case "Name" :
if (sortOrder == SortOrder.Ascending)
{
returnValue = Student1.Name.CompareTo(Student2.Name);
}
else
{
returnValue = Student2.Name.CompareTo(Student1.Name);
}
break;
case "Sex":
if (sortOrder == SortOrder.Ascending)
{
returnValue = Student1.Sex.CompareTo(Student2.Sex);
}
else
{
returnValue = Student2.Sex.CompareTo(Student1.Sex);
}
break;
default:
if (sortOrder == SortOrder.Ascending)
{
returnValue = Student1.Name.CompareTo(Student2.Name);
}
else
{
returnValue = Student2.Name.CompareTo(Student1.StudentId);
}
break;
}
return returnValue;
}
}
//---------------------------------------------------------------------------------------------
// Performing sort on click on Column Header
//---------------------------------------------------------------------------------------------
private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
//get the current column details
string strColumnName = dataGridView1.Columns[e.ColumnIndex].Name;
SortOrder strSortOrder = getSortOrder(e.ColumnIndex);
students.Sort(new StudentComparer(strColumnName, strSortOrder));
dataGridView1.DataSource = null;
dataGridView1.DataSource = students;
customizeDataGridView();
dataGridView1.Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection = strSortOrder;
}
/// <summary>
/// Get the current sort order of the column and return it
/// set the new SortOrder to the columns.
/// </summary>
/// <param name="columnIndex"></param>
/// <returns>SortOrder of the current column</returns>
private SortOrder getSortOrder(int columnIndex)
{
if (dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection == SortOrder.None ||
dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection == SortOrder.Descending)
{
dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection = SortOrder.Ascending;
return SortOrder.Ascending;
}
else
{
dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection = SortOrder.Descending;
return SortOrder.Descending;
}
}
グリッドが箱から出して基本的なソートを提供しておらず、コードが必要ないことを信じるのは難しいと思います。結局のところ、ヘッダークリックイベントを処理し、DataGridView.Sortを呼び出して、列(クリックされたものによって決定され、グリッドによって追跡される)と並べ替え方向(現在の並べ替え状態によって決定され、グリッドによって追跡される)を示す必要があるのはかなりばかげています)。
デフォルトでまったく同じことを行うSortModeまたはAllowUserToSortプロパティがないのはなぜですか?
グリッドをリストにバインドしました。列をマップしたプロパティはすべて、string、int、DateTimeなどの基本的なタイプです。これらはすべてIComparableです。では、一体なぜ1行のコードを書く必要があるのでしょうか。特にドキュメントが読むことを考えると:
デフォルトでは、ユーザーはテキストボックス列のヘッダーをクリックしてDataGridViewコントロールのデータを並べ替えることができます。
これはFramework3.0のドキュメントであり、3.5を対象としていますが、「その他のバージョン」はすべて、Frameworkのバージョンではなく、VisualStudioのバージョンを指します。ここマイクロソフトは一体何が起こっているのでしょうか?!?
この記事「SortableBindingListの提示」の良い解決策: http://www.timvw.be/2007/02/22/presenting-the-sortablebindinglistt/
これは、ReflectionとLinqを使用して列で並べ替える簡単なソリューションです。 dataGridView1のDataSourceは、次のように宣言されているcompareListに設定されます。
private List<CompareInfo> compareList;
private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
string strColumnName = dataGridView1.Columns[e.ColumnIndex].Name;
SortOrder strSortOrder = getSortOrder(e.ColumnIndex);
if (strSortOrder == SortOrder.Ascending)
{
compareList = compareList.OrderBy(x => typeof(CompareInfo).GetProperty(strColumnName).GetValue(x, null)).ToList();
}
else
{
compareList = compareList.OrderByDescending(x => typeof(CompareInfo).GetProperty(strColumnName).GetValue(x, null)).ToList();
}
dataGridView1.DataSource = compareList;
dataGridView1.Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection = strSortOrder;
}
private SortOrder getSortOrder(int columnIndex)
{
if (dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection == SortOrder.None ||
dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection == SortOrder.Descending)
{
dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection = SortOrder.Ascending;
return SortOrder.Ascending;
}
else
{
dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection = SortOrder.Descending;
return SortOrder.Descending;
}
}
public class CompareInfo
{
public string FileName { get; set; }
public string UAT_Folder { get; set; }
public string UAT_Path
{
get { return UAT_Folder + FileName; }
}
public string PROD_Folder { get; set; }
public string PROD_Path
{
get { return PROD_Folder + FileName; }
}
}
独自のユーザーコントロールを作成することが望ましい場合は、以下のコードを使用してカスタムの並べ替えメソッドを作成できます。
private string _lastSortColumn;
private ListSortDirection _lastSortDirection;
public void Sort(DataGridViewColumn column)
{
// Flip sort direction, if the column chosen was the same as last time
if (column.Name == _lastSortColumn)
_lastSortDirection = 1 - _lastSortDirection;
// Otherwise, reset the sort direction to its default, ascending
else
{
_lastSortColumn = column.Name;
_lastSortDirection = ListSortDirection.Ascending;
}
// Prep data for sorting
var data = (IEnumerable<dynamic>)DataSource;
var orderProperty = column.DataPropertyName;
// Sort data
if (_lastSortDirection == ListSortDirection.Ascending)
DataSource = data.OrderBy(x => x.GetType().GetProperty(orderProperty).GetValue(x, null)).ToList();
else
DataSource = data.OrderByDescending(x => x.GetType().GetProperty(orderProperty).GetValue(x, null)).ToList();
// Set direction of the glyph
Columns[column.Index].HeaderCell.SortGlyphDirection
= _lastSortDirection == ListSortDirection.Ascending
? SortOrder.Ascending : SortOrder.Descending;
}
次に、ヘッダークリックメソッドをオーバーライドして、並べ替え関数を呼び出すことができます。
protected override void OnColumnHeaderMouseClick(DataGridViewCellMouseEventArgs e)
{
base.OnColumnHeaderMouseClick(e);
var column = Columns[e.ColumnIndex];
if (column.SortMode == DataGridViewColumnSortMode.Automatic
|| column.SortMode == DataGridViewColumnSortMode.NotSortable)
Sort(column);
}
ListにバインドするときのDataGridViewの並べ替えの問題を解決する別のオプションは、巨大なデータセットを処理していない場合、おそらくListをDataTableに変換してから、結果のDataTableをBindingSource/DataGridViewにバインドすることです。
これには、IComparerのカスタム実装が必要になります。私の場合、より小さなリストを扱っていましたが、表示するフィールドが多かったです。したがって、IComparerを実装することは、ボイラープレートコードを書きすぎることを意味しました。
リストをDataTableに変換する簡潔な方法については、これを確認してください: https://stackoverflow.com/a/34062898/453449
この記事を参照してください
http://msdn.Microsoft.com/en-us/library/0868ft3z.aspx
これを読むと、「このメソッドは、指定された列の値を比較してDataGridViewのコンテンツを並べ替えます。デフォルトでは、並べ替え操作はCompareメソッドを使用して、DataGridViewCell .. ::を使用して列のセルのペアを比較します。値のプロパティ。」
よろしく、iordan
また、カスタマイズされたSortableBindingListを実装するための2つの興味深いリンクを取得できるこの投稿も参照してください。