对包含不同类型单元格的DataGrid列进行排序会引发ArgumentException
本文关键字:排序 ArgumentException 同类型 包含不 单元格 DataGrid | 更新日期: 2023-09-27 17:59:58
我有一个数据网格绑定到一个项目集合,该集合有一个类型为object的字段,该字段可以包含任何内容。。。布尔,字符串或任何东西。但是,当我单击列标题进行排序时,会抛出ArgumentException。我的意思是,这完全有道理,但我该如何避免这个问题。我只想将所有内容转换为字符串,并将它们作为字符串进行比较。使用转换器没有帮助。我无法更改ViewModel以对项的属性执行ToString,因此我需要一个仅视图的解决方案。
以下是一些示例代码:
XAML:
<DataGrid
ItemsSource="{Binding items}"
AutoGenerateColumns="False"
IsManipulationEnabled="False">
<DataGrid.Columns>
<DataGridTextColumn
Header="Name"
IsReadOnly="True"
Binding="{Binding Name}" />
<DataGridTextColumn
Header="Content"
IsReadOnly="True"
Binding="{Binding data, Converter={StaticResource toString}}"/>
</DataGrid.Columns>
</DataGrid>
C#:
public class MainViewModel : DependencyObject, INotifyPropertyChanged
{
public MainViewModel()
{
items = new ObservableCollection<OneItem>();
items.Add(new OneItem { Name = "Tom", Height = 180, Weight = 75, Class = 2, data = false });
items.Add(new OneItem { Name = "Dick", Height = 182, Weight = 83, Class = 3, data = true });
items.Add(new OneItem { Name = "Harry", Height = 182, Weight = 83, Class = 3, data = "Sting" });
}
public ObservableCollection<OneItem> items { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
}
public class OneItem
{
public string Name { get; set; }
public double Height { get; set; }
public double Weight { get; set; }
public double Class { get; set; }
public object data { get; set; }
}
例外:
System.Windows.Data Error: 55 : Cannot sort by 'data' InvalidOperationException:'System.InvalidOperationException: Failed to compare two elements in the array. ---> System.ArgumentException: Object must be of type Boolean.
at System.Boolean.CompareTo(Object obj)
at System.Collections.Comparer.Compare(Object a, Object b)
at MS.Internal.Data.SortFieldComparer.Compare(Object o1, Object o2)
at System.Array.SorterGenericArray.SwapIfGreaterWithItems(Int32 a, Int32 b)
at System.Array.SorterGenericArray.IntroSort(Int32 lo, Int32 hi, Int32 depthLimit)
at System.Array.SorterGenericArray.IntrospectiveSort(Int32 left, Int32 length)
--- End of inner exception stack trace ---
at System.Array.SorterGenericArray.IntrospectiveSort(Int32 left, Int32 length)
at System.Array.Sort(Array keys, Array items, Int32 index, Int32 length, IComparer comparer)
at System.Array.Sort(Array array, IComparer comparer)
at MS.Internal.Data.SortFieldComparer.SortHelper(ArrayList al, IComparer comparer)
at MS.Internal.Data.DataExtensionMethods.Sort(IList list, IComparer comparer)
at System.Windows.Data.ListCollectionView.PrepareLocalArray()
at System.Windows.Data.ListCollectionView.RefreshOverride()
at System.Windows.Data.CollectionView.RefreshInternal()
at System.Windows.Data.CollectionView.Refresh()
at System.Windows.Data.CollectionView.EndDefer()
at System.Windows.Data.CollectionView.DeferHelper.Dispose()
at System.Windows.Controls.ItemCollection.EndDefer()
at System.Windows.Controls.ItemCollection.DeferHelper.Dispose()
at System.Windows.Controls.DataGrid.DefaultSort(DataGridColumn column, Boolean clearExistingSortDescriptions)'
我添加这样的DataDisplay属性:
public class OneItem
{
public string Name { get; set; }
public double Height { get; set; }
public double Weight { get; set; }
public double Class { get; set; }
public object data { get; set; }
public object DataDisplay
{
get
{
if (data == null)
{
return string.Empty;
}
return data.ToString();
}
}
}
然后用DataDisplay替换数据,并删除绑定中的转换器:
<Grid>
<DataGrid
ItemsSource="{Binding items}"
AutoGenerateColumns="False"
IsManipulationEnabled="False">
<DataGrid.Columns>
<DataGridTextColumn
Header="Name"
IsReadOnly="True"
Binding="{Binding Name}" />
<DataGridTextColumn
Header="Content"
IsReadOnly="True"
Binding="{Binding DataDisplay}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
如果您还想要Converter。让我知道:)
最简单的方法是简单地添加(直接添加,或者通过扩展、继承或包装OneItem
)一个只返回data.ToString()
的计算属性,并将DataGridColumn绑定到该属性。你也可以避免使用转换器。
但另一种方法可能是实现DataGrid的自定义排序。
根据这里的指示,您可以创建附加的属性,以允许按列进行自定义排序,然后只需要为您的列创建一个ICustomSorter。在这种情况下,ICustomSorter将非常简单:
public class ObjectSorter : ICustomSorter
{
public System.ComponentModel.ListSortDirection SortDirection { get; set; }
public int Compare(object x, object y)
{
return x.ToString().CompareTo(y.ToString());
}
}
然后在视图Resources中声明一个,并使用该链接中描述的附加属性将其设置到列中。
<DataGrid ItemsSource="{Binding items}"
AutoGenerateColumns="False"
IsManipulationEnabled="False"
behaviours:CustomSortBehaviour.AllowCustomSort="True">
<DataGrid.Resources>
<sort:ObjectSorter x:Key="MyObjectSorter" />
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn
Header="Name"
IsReadOnly="True"
Binding="{Binding Name}" />
<DataGridTextColumn
Header="Content"
IsReadOnly="True"
Binding="{Binding data, Converter={StaticResource toString}}"
behaviours:CustomSortBehaviour.CustomSorter="{StaticResource MyObjectComparer}" />
</DataGrid.Columns>
</DataGrid>