In XAML:
<ViewModel:ListViewEx IsSortable="True" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" AutoGenerateColumns="True" />
using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media.Imaging;
public class ListViewEx : ListView
{
public bool AutoGenerateColumns
{
get { return (bool)GetValue(AutoGenerateColumnsProperty); }
set { SetValue(AutoGenerateColumnsProperty, value); }
}
public bool IsSortable
{
get { return (bool)GetValue(IsSortableProperty); }
set { SetValue(IsSortableProperty, value); }
}
public static readonly DependencyProperty AutoGenerateColumnsProperty =
DependencyProperty.Register("AutoGenerateColumns", typeof(bool), typeof(ListViewEx), new PropertyMetadata(false));
public static readonly DependencyProperty IsSortableProperty =
DependencyProperty.Register("IsSortable", typeof(Boolean), typeof(ListViewEx), new PropertyMetadata(false, OnRegisterSortableGrid));
protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue)
{
base.OnItemsSourceChanged(oldValue, newValue);
if (AutoGenerateColumns)
{
GridView gridView = new GridView();
Type sourceItemType = ItemsSource.AsQueryable().ElementType;
PropertyInfo[] properties = sourceItemType.GetProperties();
foreach (var prop in properties)
{
GridViewColumn column = new GridViewColumn();
if (prop.PropertyType == typeof(BitmapImage))
{
DataTemplate template = new DataTemplate();
FrameworkElementFactory childFactory = new FrameworkElementFactory(typeof(System.Windows.Controls.Image));
childFactory.SetBinding(System.Windows.Controls.Image.SourceProperty, new Binding(prop.Name));
childFactory.SetValue(WidthProperty, 16.0);
template.VisualTree = childFactory;
column.CellTemplate = template;
}
else
{
column.Header = (prop.GetCustomAttributes(typeof(DescriptionAttribute), false).First() as DescriptionAttribute).Description;
column.DisplayMemberBinding = new Binding(prop.Name);
column.Width = double.NaN;
}
gridView.Columns.Add(column);
}
View = gridView;
}
}
private static GridViewColumnHeader _lastHeaderClicked;
private static ListSortDirection _lastDirection;
private static ListView _listView;
private static void OnRegisterSortableGrid(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
ListView grid = obj as ListView;
if (grid != null)
{
_listView = obj as ListView;
grid.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(GridViewColumnHeaderClickedHandler));
}
}
private static void GridViewColumnHeaderClickedHandler(object sender, RoutedEventArgs e)
{
GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
if (headerClicked != null)
{
ListSortDirection direction;
if (headerClicked != _lastHeaderClicked)
{
direction = ListSortDirection.Ascending;
}
else
{
direction = _lastDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending;
}
if (headerClicked.Column.DisplayMemberBinding != null)
{
Sort((headerClicked.Column.DisplayMemberBinding as Binding).Path.Path, direction);
_lastHeaderClicked = headerClicked;
_lastDirection = direction;
}
}
}
private static void Sort(string propertyName, ListSortDirection direction)
{
var view = (ListCollectionView)CollectionViewSource.GetDefaultView(_listView.ItemsSource);
if (view != null)
{
try
{
view.CustomSort = new ListViewComparer { PropertyName = propertyName, SortDirection = direction };
_listView.Items.Refresh();
}
catch (Exception)
{
}
}
}
}
public class ListViewComparer : IComparer
{
public string PropertyName { get; set; }
public ListSortDirection SortDirection { get; set; }
public int Compare(object x, object y)
{
try
{
int result = 0;
var pro1 = x.GetType().GetProperty(PropertyName);
var pro2 = y.GetType().GetProperty(PropertyName);
var valx = pro1.GetValue(x, null);
var valy = pro2.GetValue(y, null);
if (valx == null && valy == null) return 0;
if (valx == null) return -1;
if (valy == null) return 1;
var type = pro1.PropertyType;
if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Nullable<>)))
{
type = Nullable.GetUnderlyingType(type);
}
switch (Type.GetTypeCode(type))
{
case TypeCode.String:
case TypeCode.Boolean:
result = valx.ToString().CompareTo(valy.ToString());
break;
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
result = Convert.ToDouble(valx).CompareTo(Convert.ToDouble(valy));
break;
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
result = Convert.ToInt64(valx).CompareTo(Convert.ToInt64(valy));
break;
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
result = Convert.ToUInt64(valx).CompareTo(Convert.ToUInt64(valy));
break;
case TypeCode.DateTime:
result = Convert.ToDateTime(valx).CompareTo(Convert.ToDateTime(valy));
break;
}
if (SortDirection == ListSortDirection.Descending) result *= -1;
return result;
}
catch (Exception)
{
return 0;
}
}
}
<ViewModel:ListViewEx IsSortable="True" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" AutoGenerateColumns="True" />
using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media.Imaging;
public class ListViewEx : ListView
{
public bool AutoGenerateColumns
{
get { return (bool)GetValue(AutoGenerateColumnsProperty); }
set { SetValue(AutoGenerateColumnsProperty, value); }
}
public bool IsSortable
{
get { return (bool)GetValue(IsSortableProperty); }
set { SetValue(IsSortableProperty, value); }
}
public static readonly DependencyProperty AutoGenerateColumnsProperty =
DependencyProperty.Register("AutoGenerateColumns", typeof(bool), typeof(ListViewEx), new PropertyMetadata(false));
public static readonly DependencyProperty IsSortableProperty =
DependencyProperty.Register("IsSortable", typeof(Boolean), typeof(ListViewEx), new PropertyMetadata(false, OnRegisterSortableGrid));
protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue)
{
base.OnItemsSourceChanged(oldValue, newValue);
if (AutoGenerateColumns)
{
GridView gridView = new GridView();
Type sourceItemType = ItemsSource.AsQueryable().ElementType;
PropertyInfo[] properties = sourceItemType.GetProperties();
foreach (var prop in properties)
{
GridViewColumn column = new GridViewColumn();
if (prop.PropertyType == typeof(BitmapImage))
{
DataTemplate template = new DataTemplate();
FrameworkElementFactory childFactory = new FrameworkElementFactory(typeof(System.Windows.Controls.Image));
childFactory.SetBinding(System.Windows.Controls.Image.SourceProperty, new Binding(prop.Name));
childFactory.SetValue(WidthProperty, 16.0);
template.VisualTree = childFactory;
column.CellTemplate = template;
}
else
{
column.Header = (prop.GetCustomAttributes(typeof(DescriptionAttribute), false).First() as DescriptionAttribute).Description;
column.DisplayMemberBinding = new Binding(prop.Name);
column.Width = double.NaN;
}
gridView.Columns.Add(column);
}
View = gridView;
}
}
private static GridViewColumnHeader _lastHeaderClicked;
private static ListSortDirection _lastDirection;
private static ListView _listView;
private static void OnRegisterSortableGrid(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
ListView grid = obj as ListView;
if (grid != null)
{
_listView = obj as ListView;
grid.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(GridViewColumnHeaderClickedHandler));
}
}
private static void GridViewColumnHeaderClickedHandler(object sender, RoutedEventArgs e)
{
GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
if (headerClicked != null)
{
ListSortDirection direction;
if (headerClicked != _lastHeaderClicked)
{
direction = ListSortDirection.Ascending;
}
else
{
direction = _lastDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending;
}
if (headerClicked.Column.DisplayMemberBinding != null)
{
Sort((headerClicked.Column.DisplayMemberBinding as Binding).Path.Path, direction);
_lastHeaderClicked = headerClicked;
_lastDirection = direction;
}
}
}
private static void Sort(string propertyName, ListSortDirection direction)
{
var view = (ListCollectionView)CollectionViewSource.GetDefaultView(_listView.ItemsSource);
if (view != null)
{
try
{
view.CustomSort = new ListViewComparer { PropertyName = propertyName, SortDirection = direction };
_listView.Items.Refresh();
}
catch (Exception)
{
}
}
}
}
public class ListViewComparer : IComparer
{
public string PropertyName { get; set; }
public ListSortDirection SortDirection { get; set; }
public int Compare(object x, object y)
{
try
{
int result = 0;
var pro1 = x.GetType().GetProperty(PropertyName);
var pro2 = y.GetType().GetProperty(PropertyName);
var valx = pro1.GetValue(x, null);
var valy = pro2.GetValue(y, null);
if (valx == null && valy == null) return 0;
if (valx == null) return -1;
if (valy == null) return 1;
var type = pro1.PropertyType;
if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Nullable<>)))
{
type = Nullable.GetUnderlyingType(type);
}
switch (Type.GetTypeCode(type))
{
case TypeCode.String:
case TypeCode.Boolean:
result = valx.ToString().CompareTo(valy.ToString());
break;
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
result = Convert.ToDouble(valx).CompareTo(Convert.ToDouble(valy));
break;
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
result = Convert.ToInt64(valx).CompareTo(Convert.ToInt64(valy));
break;
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
result = Convert.ToUInt64(valx).CompareTo(Convert.ToUInt64(valy));
break;
case TypeCode.DateTime:
result = Convert.ToDateTime(valx).CompareTo(Convert.ToDateTime(valy));
break;
}
if (SortDirection == ListSortDirection.Descending) result *= -1;
return result;
}
catch (Exception)
{
return 0;
}
}
}
Комментариев нет:
Отправить комментарий