C#
C# -- 정렬가능한 양방항 binding DataGridView 만들기 (SortableBindingList 와 INotifyPropertyChanged 이용)
자유프로그램
2019. 11. 28. 16:16
반응형
C# -- 정렬가능한 양방항 binding DataGridView 만들기
(SortableBindingList 와 INotifyPropertyChanged 이용)
참고 : http://martinwilley.com/net/code/forms/sortablebindinglist.html ==> SortableBindingList 출처.
** DataGridView 의 DataSource 로 BindingList 사용시에는 정렬기능 없다.
--> 이 문제를 해결한게 SortableBindingList 이다.
; BindingList 대신에 SrotableBindingList 사용하면 됨.
** DataGridView 에 연결한 DataSource 의 객체들 내부 속성에 변경사항이 생기면,
이를 즉시 DataGridView 화면에 반영하기위해서는, INotifyPropertyChanged 를 구현해야함.
--> DataGridView 화면에서 수정한 경우에도, 해당 원본 객체의 속성에 잘 반영됨.
< 실행 화면 >
< 소스코드>
--
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.ComponentModel; | |
| using System.Data; | |
| using System.Diagnostics; | |
| using System.Drawing; | |
| using System.Linq; | |
| using System.Runtime.CompilerServices; | |
| using System.Text; | |
| using System.Threading.Tasks; | |
| using System.Windows.Forms; | |
| namespace INotifyPropertyChanged_SortableBindingList_test | |
| { | |
| public partial class Form1 : Form | |
| { | |
| List<Student> studentList = new List<Student>(); | |
| private BindingSource studentBindingSource = new BindingSource(); | |
| private SortableBindingList<Student> studentBindingList; | |
| public Form1() | |
| { | |
| InitializeComponent(); | |
| studentList.Add(new Student("Tom", 17, 33.2, false)); | |
| studentList.Add(new Student("Sara", 19, 53.4, true)); | |
| studentList.Add(new Student("홍길동", 15, 130.2, false)); | |
| studentList.Add(new Student("이순신", 16, 43.2, true)); | |
| studentList.Add(new Student("Ace", 15, 23.2, false)); | |
| studentBindingList = new SortableBindingList<Student>(studentList); | |
| studentBindingSource.DataSource = studentBindingList; | |
| this.dataGridView1.DataSource = studentBindingSource; | |
| } | |
| private void Form1_Load(object sender, EventArgs e) | |
| { | |
| } | |
| // 추가 버튼 click | |
| private void button1_Click(object sender, EventArgs e) | |
| { | |
| studentBindingList.Add(new Student("유관순", 17, 45, false)); | |
| } | |
| // 삭제 버튼 click | |
| private void button2_Click(object sender, EventArgs e) | |
| { | |
| int rowIndex = this.dataGridView1.CurrentCell.RowIndex; | |
| int columnIndex = this.dataGridView1.CurrentCell.ColumnIndex; | |
| Debug.WriteLine($" 삭제될 cell ; row = {rowIndex}, column = {columnIndex}"); | |
| DataGridViewRow row = this.dataGridView1.Rows[rowIndex]; | |
| Student currentStudent = row.DataBoundItem as Student; | |
| Debug.WriteLine($"-- 삭제될 student = Name={currentStudent.Name}, Weight={currentStudent.Weight}, 안경={currentStudent.Glass}"); | |
| this.dataGridView1.Rows.RemoveAt(rowIndex); | |
| } | |
| // Info 버튼 click | |
| private void button3_Click(object sender, EventArgs e) | |
| { | |
| int rowIndex = this.dataGridView1.CurrentCell.RowIndex; | |
| int columnIndex = this.dataGridView1.CurrentCell.ColumnIndex; | |
| Debug.WriteLine($"current cell ; row = {rowIndex}, column = {columnIndex}"); | |
| //DataGridViewRow row = this.dataGridView1.SelectedRows[0]; | |
| DataGridViewRow row = this.dataGridView1.Rows[rowIndex]; | |
| Student currentStudent = row.DataBoundItem as Student; | |
| if(currentStudent != null) | |
| { | |
| Debug.WriteLine($"총 student 수 = {this.studentBindingList.Count}"); | |
| for(int i=0; i<this.studentBindingList.Count; i++) | |
| { | |
| Debug.WriteLine($" student {i} = {this.studentBindingList[i].Name}, Weight={this.studentBindingList[i].Weight}"); | |
| } | |
| Debug.WriteLine($"-- current student => {currentStudent.Name}, {currentStudent.Age}, {currentStudent.Weight}, 안경={currentStudent.Glass}"); | |
| } | |
| } | |
| // 변경 버튼 click | |
| private void button4_Click(object sender, EventArgs e) | |
| { | |
| if(this.studentBindingList.Count > 0) | |
| { | |
| Student student = this.studentBindingList[0]; | |
| student.Weight += 1; | |
| } | |
| } | |
| } | |
| public class Student : INotifyPropertyChanged | |
| { | |
| private double _weight; | |
| public string Name { get; set; } | |
| public int Age { get; set; } | |
| public double Weight | |
| { | |
| get | |
| { | |
| return _weight; | |
| } | |
| set | |
| { | |
| if (value != this._weight) | |
| { | |
| this._weight = value; | |
| NotifyPropertyChanged(); | |
| } | |
| } | |
| } | |
| public bool Glass { get; set; } = false; // 안경끼면, true | |
| public event PropertyChangedEventHandler PropertyChanged; | |
| public Student(string name, int age, double weight, bool glass) | |
| { | |
| this.Name = name; | |
| this.Age = age; | |
| this.Weight = weight; | |
| this.Glass = glass; | |
| } | |
| private void NotifyPropertyChanged([CallerMemberName] String propertyName = "") | |
| { | |
| PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); | |
| } | |
| } | |
| public class SortableBindingList<T> : BindingList<T> where T : class | |
| { | |
| private bool _isSorted; | |
| private ListSortDirection _sortDirection = ListSortDirection.Ascending; | |
| private PropertyDescriptor _sortProperty; | |
| public SortableBindingList() | |
| { | |
| } | |
| public SortableBindingList(IList<T> list) | |
| : base(list) | |
| { | |
| } | |
| // Gets a value indicating whether the list supports sorting. | |
| protected override bool SupportsSortingCore | |
| { | |
| get { return true; } | |
| } | |
| // Gets a value indicating whether the list is sorted. | |
| protected override bool IsSortedCore | |
| { | |
| get { return _isSorted; } | |
| } | |
| // Gets the direction the list is sorted. | |
| protected override ListSortDirection SortDirectionCore | |
| { | |
| get { return _sortDirection; } | |
| } | |
| // Gets the property descriptor that is used for sorting the list if sorting is implemented in a derived class; otherwise, returns null | |
| protected override PropertyDescriptor SortPropertyCore | |
| { | |
| get { return _sortProperty; } | |
| } | |
| // Removes any sort applied with ApplySortCore if sorting is implemented | |
| protected override void RemoveSortCore() | |
| { | |
| _sortDirection = ListSortDirection.Ascending; | |
| _sortProperty = null; | |
| _isSorted = false; //thanks Luca | |
| } | |
| // Sorts the items if overridden in a derived class | |
| protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction) | |
| { | |
| _sortProperty = prop; | |
| _sortDirection = direction; | |
| List<T> list = Items as List<T>; | |
| if (list == null) return; | |
| list.Sort(Compare); | |
| _isSorted = true; | |
| //fire an event that the list has been changed. | |
| OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); | |
| } | |
| private int Compare(T lhs, T rhs) | |
| { | |
| var result = OnComparison(lhs, rhs); | |
| //invert if descending | |
| if (_sortDirection == ListSortDirection.Descending) | |
| result = -result; | |
| return result; | |
| } | |
| private int OnComparison(T lhs, T rhs) | |
| { | |
| object lhsValue = lhs == null ? null : _sortProperty.GetValue(lhs); | |
| object rhsValue = rhs == null ? null : _sortProperty.GetValue(rhs); | |
| if (lhsValue == null) | |
| { | |
| return (rhsValue == null) ? 0 : -1; //nulls are equal | |
| } | |
| if (rhsValue == null) | |
| { | |
| return 1; //first has value, second doesn't | |
| } | |
| if (lhsValue is IComparable) | |
| { | |
| return ((IComparable)lhsValue).CompareTo(rhsValue); | |
| } | |
| if (lhsValue.Equals(rhsValue)) | |
| { | |
| return 0; //both are the same | |
| } | |
| //not comparable, compare ToString | |
| return lhsValue.ToString().CompareTo(rhsValue.ToString()); | |
| } | |
| } | |
| } |
반응형