使用绑定数据和转换器对datagrid列进行排序

时间:2012-07-25 14:07:13

标签: .net wpf xaml mvvm

我正在尝试对datagrid中的数据进行排序,但是当我点击与转换器绑定的列的标题时,没有任何反应。我使用MVVM模式。示例如下。在该示例中,网格显示列(类型),其显示人的类型,因此我使用转换器(类TypeValueConverter)。当我使用此转换器时,网格不会对列类型进行排序。

<Window x:Class="GridSort.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:GridSort"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DataGrid ItemsSource="{Binding People}" AutoGenerateColumns="False">
            <DataGrid.Resources>
                <my:TypeValueConverter x:Key="typeConverter" />
            </DataGrid.Resources>
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding FirstName}" Header="FirstName" />
                <DataGridTextColumn Binding="{Binding Surname}" Header="Surname" />
                <DataGridTextColumn Binding="{Binding Converter={StaticResource ResourceKey=typeConverter}}" Header="Type" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>
public class ViewModel
{
    private ICollection<Person> people;
    public ICollection<Person> People
    {
        get
        {
            if (this.people == null)
            {
                this.people = new List<Person>();
                this.people.Add(new Student() { FirstName = "Charles", Surname = "Simons" });
                this.people.Add(new Student() { FirstName = "Jake", Surname = "Baron" });
                this.people.Add(new Teacher() { FirstName = "John", Surname = "Jackson" });
                this.people.Add(new Student() { FirstName = "Patricia", Surname = "Phillips" });
                this.people.Add(new Student() { FirstName = "Martin", Surname = "Weber" });
            }

            return this.people;
        }
    }
}

public class TypeValueConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null)
            {
                return DependencyProperty.UnsetValue;
            }

            return value.GetType().Name;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

public abstract class Person
    {
        public string FirstName
        {
            get;
            set;
        }

        public string Surname
        {
            get;
            set;
        }
    }

    public class Student : Person
    {
    }

    public class Teacher : Person
    {
    }

3 个答案:

答案 0 :(得分:7)

我自己解决了这个问题:)

我使用附加属性UseBindingToSort为网格创建了新行为。当我将此属性设置为true时,将订阅事件在网格上排序。在网格触发事件排序之后,我使用自定义比较器和IValueConverter,它在绑定中定义。 解决方案如下:

更改视图

<DataGrid ItemsSource="{Binding People}" AutoGenerateColumns="False"  my:GridSortingBehavior.UseBindingToSort="True">

附加属性的新行为:

public static class GridSortingBehavior
    {
        public static readonly DependencyProperty UseBindingToSortProperty = DependencyProperty.RegisterAttached("UseBindingToSort", typeof(bool), typeof(GridSortingBehavior), new PropertyMetadata(new PropertyChangedCallback(GridSortPropertyChanged)));

        public static void SetUseBindingToSort(DependencyObject element, bool value)
        {
            element.SetValue(UseBindingToSortProperty, value);
        }

        private static void GridSortPropertyChanged(DependencyObject elem, DependencyPropertyChangedEventArgs e)
        {
            DataGrid grid = elem as DataGrid;
            if (grid != null){
                if ((bool)e.NewValue)
                {
                    grid.Sorting += new DataGridSortingEventHandler(grid_Sorting);
                }
                else
                {
                    grid.Sorting -= new DataGridSortingEventHandler(grid_Sorting);
                }
            }
        }

        static void grid_Sorting(object sender, DataGridSortingEventArgs e)
        {
            DataGridTextColumn clm = e.Column as DataGridTextColumn;
            if (clm != null)
            {
                DataGrid grid = ((DataGrid)sender);
                IValueConverter converter = null;
                if (clm.Binding != null)
                {
                    Binding binding = clm.Binding as Binding;
                    if (binding.Converter != null)
                    {
                        converter = binding.Converter;
                    }
                }

                if (converter != null)
                {
                    e.Handled = true;
                    ListSortDirection direction = (clm.SortDirection != ListSortDirection.Ascending) ? ListSortDirection.Ascending : ListSortDirection.Descending;
                    clm.SortDirection = direction;
                    ListCollectionView lcv = (ListCollectionView)CollectionViewSource.GetDefaultView(grid.ItemsSource);
                    lcv.CustomSort = new ComparerWithComparer(converter, direction);
                }
            }
        }

最后我的自定义比较器:

class ComparerWithComparer : IComparer
    {
        private System.Windows.Data.IValueConverter converter;
        private System.ComponentModel.ListSortDirection direction;


        public ComparerWithComparer(System.Windows.Data.IValueConverter converter, System.ComponentModel.ListSortDirection direction)
        {
            this.converter = converter;
            this.direction = direction;
        }

        public int Compare(object x, object y)
        {
            object transx = this.converter.Convert(x, typeof(string), null, System.Threading.Thread.CurrentThread.CurrentCulture);
            object transy = this.converter.Convert(y, typeof(string), null, System.Threading.Thread.CurrentThread.CurrentCulture);
            if (direction== System.ComponentModel.ListSortDirection.Ascending){
                return Comparer.Default.Compare(transx, transy);
            }
            else
            {
                return Comparer.Default.Compare(transx, transy) * (-1);
            }
        }
    }

就是这样。

答案 1 :(得分:1)

您正在使用MVVM。如果您无法将属性Type添加到Person

public abstract class Person
{
    public string FirstName { get; set; }

    public string Surname { get; set; }

    public string Type
    {
        get { return this.GetType().Name; }
    }
}

你应该创建一个PersonViewModel

public class PersonViewModel
{
    public Person Person { get; private set; }

    public PersonViewModel(Person person)
    {
        this.Person = person;
    }

    public string Type
    {
        get { return this.Person.GetType().Name; }
    }
}

调整您的People系列

private ICollection<PersonViewModel> people;
public ICollection<PersonViewModel> People
{
    get
    {
        if (this.people == null)
        {
            this.people = new List<PersonViewModel>();
            this.people.Add(new PersonViewModel(new Student { FirstName = "Charles", Surname = "Simons" }));
            this.people.Add(new PersonViewModel(new Student { FirstName = "Jake", Surname = "Baron" }));
            this.people.Add(new PersonViewModel(new Teacher { FirstName = "John", Surname = "Jackson" }));
            this.people.Add(new PersonViewModel(new Student { FirstName = "Patricia", Surname = "Phillips" }));
            this.people.Add(new PersonViewModel(new Student { FirstName = "Martin", Surname = "Weber" }));
        }
        return this.people;
    }
}

并使用此XAML

<DataGrid.Columns>
    <DataGridTextColumn Binding="{Binding Person.FirstName}" Header="FirstName" />
    <DataGridTextColumn Binding="{Binding Person.Surname}" Header="Surname" />
    <DataGridTextColumn Binding="{Binding Type}" Header="Type" />
</DataGrid.Columns>

答案 2 :(得分:1)

我使用了Juptin的解决方案。但在我的情况下,我使用ConverterParameter。 所以我将它添加到他的代码中:

class ComparerWithComparer : IComparer
{
    private IValueConverter converter;
    private ListSortDirection direction;
    private object parameter;

    public ComparerWithComparer(IValueConverter converter, ListSortDirection direction, object parameter)
    {
        this.converter = converter;
        this.direction = direction;
        this.parameter = parameter;
    }

    public int Compare(object x, object y)
    {
        object transx = converter.Convert(x, typeof(string), parameter, System.Threading.Thread.CurrentThread.CurrentCulture);
        object transy = converter.Convert(y, typeof(string), parameter, System.Threading.Thread.CurrentThread.CurrentCulture);
        if (direction == ListSortDirection.Ascending)
        {
            return Comparer.Default.Compare(transx, transy);
        }
        return Comparer.Default.Compare(transx, transy) * (-1);
    }
}
static void grid_Sorting(object sender, DataGridSortingEventArgs e)
{
    DataGridTextColumn column = e.Column as DataGridTextColumn;
    if (column != null)
    {
        DataGrid grid = ((DataGrid)sender);
        IValueConverter converter = null;
        object parameter = null;
        if (column.Binding != null)
        {
            Binding binding = column.Binding as Binding;
            if (binding.Converter != null)
            {
                converter = binding.Converter;
            }
            parameter = binding.ConverterParameter;
        }

        if (converter != null)
        {
            e.Handled = true;
            ListSortDirection direction = (column.SortDirection != ListSortDirection.Ascending) ? ListSortDirection.Ascending : ListSortDirection.Descending;
            column.SortDirection = direction;
            var listCollectionView = (ListCollectionView)CollectionViewSource.GetDefaultView(grid.ItemsSource);
            listCollectionView.CustomSort = new ComparerWithComparer(converter, direction,parameter);
        }
    }
}