четверг, 31 мая 2012 г.

ListView autogenerate columns and sort on header click wpf mvvm

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



Комментариев нет:

Отправить комментарий