2015-06-26 6 views
2

У меня есть datagrid, связанный с набором элементов, которые имеют поле типа объекта, которое может содержать что угодно ... bool, string или что угодно. Но когда я нажимаю на заголовок столбца для сортировки, возникает ArgumentException. Я имею в виду, что это имеет смысл, но все же как я могу избежать этой проблемы. Все, что я хочу, - это преобразовать все в строку и сравнить их как строки. Использование конвертера не помогает. Я не могу изменить ViewModel, чтобы сделать ToString по свойству элемента, поэтому мне нужно только представление.Сортировка столбца DataGrid, содержащего разные типы ячеек throws ArgumentException

Вот некоторые примеры кода:

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)' 
+0

Самый простой approcach бы просто добавить (непосредственно или путем расширения или inheritng от 'OneItem') вычисляемого свойства, которое просто возвращает' data.ToString() ', и связать свой DataGridColumn к этому свойству вместо Вы также избегайте использования конвертера. – almulo

+0

Да, подход VM был бы самым простым, но я не хочу загромождать свою виртуальную машину для проблемы, которая возникает в одном незначительном месте, и моя виртуальная машина используется в нескольких местах для большего количества импов. задания. – schwarz

+1

Хорошо, я отправляю другое решение, которое немного сложнее, но только для просмотра. – almulo

ответ

1

Простейший подход будет просто добавлять (напрямую или путем наложения или наследования или обертывания вашего OneItem) вычисленного свойства, которое просто возвращает data.ToString() и вместо этого привязывает ваш DataGridColumn к этому свойству. Таким образом, вы также избегаете использования конвертера.

Но другим способом может быть реализация пользовательской сортировки DataGrid.

Following the indications here вы можете создавать прикрепленные свойства, чтобы разрешить выборочную сортировку в столбцах, а затем вам просто нужно создать 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()); 
    } 
} 

Затем объявить один на ваш взгляд ресурсов и установить его на колонке с использованием прикрепленных свойств, описанных в этой ссылке.

<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> 
+1

Спасибо и поздравляю вас с знаком 1K rep: P – schwarz

+0

Спасибо вам! :) – almulo

2

добавить 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> 

Если вы хотите конвертер. Дайте мне знать :)

Смежные вопросы