[原][十万个为什么]__DataGrid项使用多绑定导致排序失效

描述: 在Wpf中, 经常用的ListView控件无疑是DataGrid.使用DataGird无疑会使用数据绑定.一般来说都是先将DataGrid的ItemSource绑定到需要的Model上.然后为各个Column指定绑定路径.就像如下写法.

在.xaml中:

        <DataGrid x:Name="carlist" ItemsSource="{Binding}" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Width="100" Header="车名" Binding="{Binding Path=CarName}" />
                <DataGridTextColumn Width="100" Header="颜色" Binding="{Binding Path=Color}" />
            </DataGrid.Columns>
        </DataGrid>

而在.cs中:

 /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public Cars Cars = new Cars();
        public MainWindow()
        {
            InitializeComponent();
            carlist.DataContext = Cars;
        }
    }

    public class Cars : ObservableCollection<Car>
    {
        public Cars()
        {
            base.Add(new Car("东风哥1号", "Red"));
            base.Add(new Car("东风哥2号", "Yellow"));
        }
    }

    public class Car
    {
        public Car(string name, string color)
        {
            CarName = name;
            Color = color;
        }

        public string CarName { get; set; }
        public string Color { get; set; }
    }
 

    这样你就将一个Car集合Cars(一般Cars都得从ObserveCollection中派生出来.这样具有修改自动通知的功能).当然该Car模型里面具有两个公开属性: CarName和Color绑定到了这个DataGrid上.嗯,这样绑定是没有任何问题的.就算运行点击Header排序也会利用反射机制根据Car的属性进行排列.换句话说,排列也是不需要自己写的.但是值得注意的是,这种排序并非在原来的Cars上进行排序.而是创建一个虚拟视图ListCollectionView.然后在视图上排序.也就不会影响到原来Cars的内容.这种机制类似与数据库的视图.这样的话,对于DataGrid的分组,筛选,排序就可以直接通过获取该DataGrid.ItemSource的视图ListCollectionView进行操作.当然这不是本节的重点.运行效果如下:

image

     想必你已经对DataGrid有一个大概的认识.让我们来点更深层次的.我们假设业务现在变更了.Car里面多了两个属性.厂商Manufacturer和型号Type. 你可能会想,这不很容易么? 在DataGrid.Columns下面加多两个DataGridTextColumn不就行了么?可是,哎呀,老板说这样显示信息太杂太难看.你把厂商和型号合起来作为一个列吧形式为: [Manufacturer]+.+[Type] 作为一列. 例如: '东风.P11'.这时候无疑得写个Converter类型转化器. 好吧.开始搞吧.那么.cs应该改成这样:

.cs中:

 public class Cars : ObservableCollection<Car>
    {
        public Cars()
        {
            base.Add(new Car("东风哥1号", "Red", "东风", "P11"));
            base.Add(new Car("东风哥2号", "Yellow", "西风", "F4"));
        }
    }

    public class Car
    {
        public Car(string name, string color,
                   string manu, string type)
        {
            CarName = name;
            Color = color;
            Manufacturer = manu;
            Type = type;
        }

        public string CarName { get; set; }
        public string Color { get; set; }
        public string Manufacturer { get; set; }
        public string Type { get; set; }
    }  
此时,编写一个InfoConverter并实现IMutiConverter接口.它是用来将绑定的两个属性转化成一个可视化对象.
代码如下: 
    public class InfoConverter : IMultiValueConverter
    {

        #region IMultiValueConverter 成员

        public object Convert(object[] values, Type targetType,
            object parameter, System.Globalization.CultureInfo culture)
        {
            //values[0]就是你第一个绑定的值
            //values[1]就是你第二个绑定的值
            //其他参数系统会处理.
            string manu = (string)values[0];
            string type = (string)values[1];
            return manu + "." + type;
        }

        public object[] ConvertBack(object value, Type[] targetTypes,
            object parameter, System.Globalization.CultureInfo culture)
        {
            //因为我们不需要编辑列表所以自然也不需要反向转化.
            throw new NotImplementedException();
        }

        #endregion
}

好了继续我们的xaml:

首先声明该Converter变量:

<Window.Resources>
    <local:InfoConverter x:Key="converter" />
</Window.Resources>

接着在DataGrid中在添加一个DataGridTextColumn

<DataGridTextColumn Width="100" Header="车辆信息">
     <DataGridTextColumn.Binding>
           <MultiBinding Converter="{StaticResource converter}">
                  <Binding Path="Manufacturer" />
                  <Binding Path="Type" />
           </MultiBinding>
     </DataGridTextColumn.Binding>
</DataGridTextColumn>

运行效果如下:

image

好吧.任务完成.难道这一切都完成了吗...都顺利完成的话就不会有这篇文章了.这时你会发现车辆信息这一列点击无法排序了.

......一轮又一轮的百度,Google......

还是没找出解决方案.当然这是我们这种菜鸟的做饭.最后项目组的一个高手,为我揭开了谜题.告诉我这个是通过反射机制来根据属性名称来排序.当然我们车辆信息这一列在Car中是不存在的.所以排序自然就无效啦.最后经他指点.通过监听Sort事件来改造该DataGrid.不多说代码如下:

/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
    public Cars Cars = new Cars();
    public MainWindow()
    {
        InitializeComponent();
        carlist.DataContext = Cars;

        //监听Sorting事件
        carlist.Sorting += new DataGridSortingEventHandler(carlist_Sorting);

       
    }

    void carlist_Sorting(object sender, DataGridSortingEventArgs e)
    {
        if (e.Column.Header.ToString() == "车辆信息")
        {

            //进行用户自定义排序记得这里是对view的排序.
            ListCollectionView lview = (ListCollectionView)
                CollectionViewSource.GetDefaultView(carlist.ItemsSource);
            lview.CustomSort = new CarInfoCompareAsc();
        }
    }

    class CarInfoCompareAsc : IComparer
    {

        #region IComparer 成员

        public int Compare(object x, object y)
        {
            string a = (x as Car).Manufacturer + "." +
                (x as Car).Type;
            string b = (y as Car).Manufacturer + "." +
                (y as Car).Type;

            return a.CompareTo(b);
        }

        #endregion
    }
}

ok,当你再次运行的时候"车辆信息"这一列已经能够排序了.但是只是升序而已.也就是说不能进行降序.至于如何进行降序这个问题就留给读者自己去想了.....

源代码下载: https://files.cnblogs.com/kingmoon/DataGrid_MutiBinding__cnblog_Kingmoon.zip

转载请标明: http://www.cnblogs.com/kingmoon/

posted on 2011-07-16 10:54  kingmoon  阅读(1305)  评论(1编辑  收藏  举报

导航