当DataGrid使用对象进行了分组时候,该对象类型必须实现 IComparable 接口,否则出错:必须至少有一个对象实现。 ObservableCollection<TaskProject> list1 = new ObservableCollection<TaskProject>(); for (int i = 1; i <= 2; i++) { list1.Add(new TaskProject() { ProjectId = i, ProjectName = "Project " + i.ToString(), }); } list1.Add(new TaskProject() { ProjectId = 1, ProjectName = "Project 1" }); this.dataGrid2.ItemsSource = new PagedCollectionView(list1); ObservableCollection<Task> taskList = new ObservableCollection<Task>(); // Generate some task data and add it to the task list. for (int i = 1; i <= 100; i++) { taskList.Add(new Task() { Area = i / 3D, ProjectName = "公司 " + ((i % 5) + 1).ToString(), TaskName = "Task " + i.ToString(), Project = list1[i % list1.Count], DueDate = DateTime.Now.AddDays(i), Complete = (i % 2 == 0), Notes = "Task " + i.ToString() + " is due on " + DateTime.Now.AddDays(i) + ". Lorum ipsum..." }); } PagedCollectionView taskListView = new PagedCollectionView(taskList); taskListView.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(taskListView_CollectionChanged); this.dataGrid1.ItemsSource = taskListView; if (taskListView.CanGroup == true) { PropertyGroupDescription group = new PropertyGroupDescription("Project"); group.Converter = new ProjectConverter(); taskListView.GroupDescriptions.Add(group); // Then group by Complete status. taskListView.GroupDescriptions.Add(new PropertyGroupDescription("Complete")); } if (taskListView.CanSort == true) { // By default, sort by ProjectName. taskListView.SortDescriptions.Add(new SortDescription("ProjectName", ListSortDirection.Ascending)); } dataPager1.Source = taskListView; public class TaskProject : IComparable, IComparable<TaskProject> { public int ProjectId { get; set; } public string ProjectName { get; set; } public override string ToString() { return this.ProjectName; } #region IComparable 成员 public int CompareTo(object obj) { return this.CompareTo(obj as TaskProject); } #endregion #region IComparable<TaskProject> 成员 public int CompareTo(TaskProject other) { if (other == null) { return -1; } return this.ProjectId - other.ProjectId; } #endregion } public class ProjectConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return (value as TaskProject).ProjectName; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return 0; } } public class Task : System.ComponentModel.INotifyPropertyChanged, IEditableObject { // The Task class implements INotifyPropertyChanged and IEditableObject // so that the datagrid can properly respond to changes to the // data collection and edits made in the DataGrid. // Private task data. private string m_ProjectName = string.Empty; private string m_TaskName = string.Empty; private DateTime m_DueDate = DateTime.Now; private bool m_Complete = false; private string m_Notes = string.Empty; // Data for undoing canceled edits. private Task temp_Task = null; private bool m_Editing = false; public double Area { get; set; } // Public properties. [Display(Name = "公司")] public string ProjectName { get { return this.m_ProjectName; } set { if (value != this.m_ProjectName) { this.m_ProjectName = value; NotifyPropertyChanged("ProjectName"); } } } [Display(Name = "项目")] public TaskProject Project { get; set; } [Display(Name = "Task")] public string TaskName { get { return this.m_TaskName; } set { if (value != this.m_TaskName) { this.m_TaskName = value; NotifyPropertyChanged("TaskName"); } } } [Display(Name = "Due Date")] public DateTime DueDate { get { return this.m_DueDate; } set { if (value != this.m_DueDate) { this.m_DueDate = value; NotifyPropertyChanged("DueDate"); } } } public bool Complete { get { return this.m_Complete; } set { if (value != this.m_Complete) { this.m_Complete = value; NotifyPropertyChanged("Complete"); } } } public string Notes { get { return this.m_Notes; } set { if (value != this.m_Notes) { this.m_Notes = value; NotifyPropertyChanged("Notes"); } } } // Implement INotifyPropertyChanged interface. public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } // Implement IEditableObject interface. public void BeginEdit() { if (m_Editing == false) { temp_Task = this.MemberwiseClone() as Task; m_Editing = true; } } public void CancelEdit() { if (m_Editing == true) { this.ProjectName = temp_Task.ProjectName; this.TaskName = temp_Task.TaskName; this.DueDate = temp_Task.DueDate; this.Complete = temp_Task.Complete; this.Notes = temp_Task.Notes; m_Editing = false; } } public void EndEdit() { if (m_Editing == true) { temp_Task = null; m_Editing = false; } } }