对包含不同类型的单元格的DataGrid列进行排序会抛出ArgumentException

时间:2015-06-26 13:11:03

标签: c# wpf datagrid

我有一个datagrid绑定到一个项目集合,这些项目有一个object类型的字段,可以包含任何东西...... bool,string或者其他东西。但是当我单击列标题进行排序时,会抛出ArgumentException。我的意思是它完全有道理,但我仍然可以避免这个问题。我想要的是将所有内容转换为字符串并将它们作为字符串进行比较。使用转换器没有帮助。我无法更改ViewModel来对项目属性执行ToString,因此我需要一个仅查看解决方案。

以下是一些示例代码:

XAML:

puppet apply --modulepath=/path_to_modules -e "include roles::database"

C#:

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

例外:

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; }
}

2 个答案:

答案 0 :(得分: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替换数据并删除绑定中的Converter:

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

如果你也想要转换器。让我知道:))

答案 1 :(得分: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());
    }
}

然后在您的视图中声明一个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>