描述: 在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; } }
想必你已经对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>
运行效果如下:
好吧.任务完成.难道这一切都完成了吗...都顺利完成的话就不会有这篇文章了.这时你会发现车辆信息这一列点击无法排序了.
......一轮又一轮的百度,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,当你再次运行的时候"车辆信息"这一列已经能够排序了.但是只是升序而已.也就是说不能进行降序.至于如何进行降序这个问题就留给读者自己去想了.....
源代码下载: http://files.cnblogs.com/kingmoon/DataGrid_MutiBinding__cnblog_Kingmoon.zip