Dynamic Column & Custom Sorting

3 posts, 0 answers
  1. Ludovic Alcala
    Ludovic Alcala avatar
    24 posts
    Member since:
    Jan 2010

    Posted 03 Mar 2010 Link to this post

    Hello,
    i have a project where we have this kind of object :

    - ListingProduct (DisplayName, List<property>) which properties is  a Property {string name, string value}.

    And i need to offer to my users the choice of shown column (who correspond to properties) by a context menu on header fields.

    Here the code :
    using System; 
    using System.Net; 
    using System.Windows; 
    using System.Windows.Controls; 
    using System.Windows.Documents; 
    using System.Windows.Ink; 
    using System.Windows.Input; 
    using System.Windows.Media; 
    using System.Windows.Media.Animation; 
    using System.Windows.Shapes; 
    using System.ComponentModel; 
    using Telerik.Windows.Controls; 
    using Telerik.Windows.Controls.GridView; 
    using Telerik.Windows; 
    using System.Windows.Data; 
    using System.Collections.Generic; 
    using System.Linq; 
    using CatalogManager.WCFCatalogManager; 
    using System.Collections.ObjectModel; 
    using Telerik.Windows.Data; 
    using System.Collections; 
    using System.Diagnostics; 
    namespace CatalogManager.Views.CatalogV.Renderer 
        public class HeaderColumnChooser 
        { 
     
            private RadGridView grid = null
            public HeaderColumnChooser(RadGridView grid) 
            { 
                this.grid = grid; 
            } 
     
            public static readonly DependencyProperty IsEnabledProperty 
                = DependencyProperty.RegisterAttached("IsEnabled"typeof(bool), typeof(HeaderColumnChooser), 
                    new System.Windows.PropertyMetadata(new PropertyChangedCallback(OnIsEnabledPropertyChanged))); 
     
            public static void SetIsEnabled(DependencyObject dependencyObject, bool enabled) 
            { 
                dependencyObject.SetValue(IsEnabledProperty, enabled); 
            } 
     
            public static bool GetIsEnabled(DependencyObject dependencyObject) 
            { 
                return (bool)dependencyObject.GetValue(IsEnabledProperty); 
            } 
     
            private static void OnIsEnabledPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
            { 
                RadGridView grid = dependencyObject as RadGridView; 
                if (grid != null
                { 
                    if ((bool)e.NewValue) 
                    { 
                        // Create new GridViewHeaderMenu and attach RowLoaded event. 
                        HeaderColumnChooser menu = new HeaderColumnChooser(grid); 
                        menu.Attach(); 
     
     
                    } 
                } 
            } 
            private void Attach() 
            { 
                if (grid != null
                { 
                    this.grid.Loaded += new RoutedEventHandler(grid_Loaded); 
                    this.grid.DataLoaded += new EventHandler<EventArgs>(grid_DataLoaded); 
                    this.grid.Sorting += new EventHandler<GridViewSortingEventArgs>(grid_Sorting); 
                    this.grid.Sorted += new EventHandler<GridViewSortedEventArgs>(grid_Sorted); 
                    this.grid.SortDescriptors.Clear(); 
                } 
            } 
     
            
     
     
            void grid_Sorted(object sender, GridViewSortedEventArgs e) 
            { 
                e.Handled = true
            } 
            private SortingState st { getset; } 
            private string ns { getset; } 
            void grid_Sorting(object sender, GridViewSortingEventArgs e) 
            { 
                string action = ""
                if (e.NewSortingState == SortingState.Ascending) 
                    action = "SortAsc"
                else if (e.NewSortingState == SortingState.Descending) 
                    action = "SortDesc"
                else 
                    action = "ClearSort"
                SortGrid(e.Column, action); 
                ns = e.Column.UniqueName; 
                if (e.OldSortingState == SortingState.None) 
                { 
                    e.NewSortingState = SortingState.Ascending; 
                     
                } 
                else if (e.OldSortingState == SortingState.Ascending) 
                { 
                    e.NewSortingState = SortingState.Descending; 
                     
                } 
                else 
                { 
                    e.NewSortingState = SortingState.None; 
                     
                } 
                e.Column.SortingState = e.NewSortingState; 
                e.Cancel = true
     
            } 
     
            void grid_DataLoaded(object sender, EventArgs e) 
            { 
                GridViewHeaderRow headerRow = grid.ChildrenOfType<GridViewHeaderRow>().FirstOrDefault(); 
                if (headerRow != null
                { 
                    InitializeMenus(headerRow); 
                } 
            } 
     
            void grid_Loaded(object sender, RoutedEventArgs e) 
            { 
     
            } 
     
            private void InitializeMenus(GridViewHeaderRow row) 
            { 
                IEnumerable<GridViewHeaderCell> cells = row.Cells.OfType<GridViewHeaderCell>(); 
     
                foreach (GridViewHeaderCell cell in cells) 
                { 
                    // create menu 
                    RadContextMenu contextMenu = new RadContextMenu(); 
                    // set menu Theme 
                    StyleManager.SetTheme(contextMenu, StyleManager.GetTheme(grid)); 
     
                    RadMenuItem item = new RadMenuItem() { Name = "SortAsc", Header = String.Format(@"Trier par ordre croissant par ""{0}""", cell.Column.Header) }; 
                    contextMenu.Items.Add(item); 
     
                    item = new RadMenuItem() { Name = "SortDesc", Header = String.Format(@"Trier par ordre décroissant par ""{0}""", cell.Column.Header) }; 
                    contextMenu.Items.Add(item); 
     
                    item = new RadMenuItem() { Name = "ClearSort", Header = String.Format(@"Effacer le tri de ""{0}""", cell.Column.Header) }; 
                    contextMenu.Items.Add(item); 
     
                    item = new RadMenuItem() { Name = "ChooseColumns", Header = "Choisir les colonnes" }; 
                    contextMenu.Items.Add(item); 
     
     
                    contextMenu.AddHandler(RadMenuItem.ClickEvent, new RoutedEventHandler(OnMenuItemClick)); 
     
                    // attach menu 
                    RadContextMenu.SetContextMenu(cell, contextMenu); 
                } 
            } 
     
            void OnMenuItemClick(object sender, RoutedEventArgs e) 
            { 
                RadContextMenu menu = (RadContextMenu)sender; 
                RadMenuItem clickedItem = ((RadRoutedEventArgs)e).OriginalSource as RadMenuItem; 
                GridViewColumn column = ((GridViewHeaderCell)menu.UIElement).Column; 
     
                if (clickedItem.Parent is RadMenuItem) 
                    return
     
                string header = Convert.ToString(clickedItem.Name); 
                if (header == "ChooseColumns"
                { 
                    ObservableCollection<InfoPropSchema> props; 
                    props = (grid.ParentOfType<CatalogProducts>()).propsSchema; 
                    ChooseProperties chooseProperties = new ChooseProperties(props); 
                    chooseProperties.Closing += new EventHandler<CancelEventArgs>(chooseProperties_Closing); 
                    chooseProperties.Show(); 
                    return
                } 
                SortGrid(column, header); 
            } 
            void SortGrid(GridViewColumn column, string action) 
            { 
                if (grid.Columns.Count > 4)  
                Debug.WriteLine(System.DateTime.Now.ToString() + " " + grid.Columns[4].SortingState + " - SortGridStart"); 
                using (grid.DeferRefresh()) 
                { 
                    InfoPropSchema ips = (grid.ParentOfType<CatalogProducts>()).propsSchema.First(o => o.Name == column.UniqueName); 
                    SortedCollection<ListingCatalogItem> soc = new SortedCollection<ListingCatalogItem>(new sortInfoProp(ips)); 
                    ObservableCollection<ListingCatalogItem> list; 
                    if ((grid.ParentOfType<CatalogProducts>()).MyDefinitionType == DefinitionType.ProductDefinition) 
                    { 
                        list = ((grid.ParentOfType<CatalogProducts>()).MyCollection); 
                    } 
                    else 
                    { 
                        list = ((grid.ParentOfType<CatalogProducts>()).MyCollectionSousCategories); 
                    } 
                    switch (action) 
                    { 
                        case "SortAsc"
                            list.ToList().ForEach(o => soc.Add(o)); 
                            list.Clear(); 
                            soc.ToList().ForEach(o => list.Add(o)); 
                            (grid.ItemsSource as QueryableCollectionView).Refresh(); 
                            soc.Clear(); 
                            soc = null
                            break
                        case "SortDesc"
                            list.ToList().ForEach(o => soc.Add(o)); 
                            list.Clear(); 
                            soc.Reverse().ToList().ForEach(o => list.Add(o)); 
                            (grid.ItemsSource as QueryableCollectionView).Refresh(); 
                            soc.Clear(); 
                            soc = null
                            break
                        case "ClearSort"
     
                            break
                    } 
                } 
            } 
            void chooseProperties_Closing(object sender, CancelEventArgs e) 
            { 
                Reload(true); 
            } 
     
            public void Reload(bool rebind) 
            { 
                GridViewColumnCollection gvcc = new GridViewColumnCollection(); 
                grid.SortDescriptors.Clear(); 
                grid.Columns.Clear(); 
                grid.Columns.Add(new GridViewToggleRowDetailsColumn() 
                { 
                    Header = "QuickEdit" 
                }); 
                (grid.ParentOfType<CatalogProducts>()).propsSchema.Where(o => o.IsShown).ToList().ForEach( 
                      delegate(InfoPropSchema a) 
                      { 
                          if (!gvcc.Any<GridViewColumn>(o => o != null && o.UniqueName == a.Name)) 
                          { 
                              Binding myBind = new Binding("ListProperties"
                              { 
                                  Converter = new ListPropriete(a), 
                                  ConverterParameter = a.Name 
                              }; 
     
                              gvcc.Add( 
                                  new GridViewDataColumn() 
                                  { 
                                      Header = a.DisplayName, 
                                      DataMemberBinding = myBind, 
                                      UniqueName = a.Name, 
                                      IsReorderable = false
                                      IsFilterable = false
                                      IsSortable=true
                                      SortMemberPath = a.Name, 
                                      DataType = typeof(String) 
                                  } 
                              ); 
                          } 
                      }); 
     
     
                gvcc.ToList<GridViewColumn>().ForEach(o => grid.Columns.Add(o)); 
                if (rebind) 
                    grid.Rebind(); 
            } 
     
        } 
        public class sortInfoProp : IComparer<ListingCatalogItem> 
        { 
            private InfoPropSchema _propertyNameToSort; 
            public sortInfoProp(InfoPropSchema propertyNameToSort) 
            { 
                _propertyNameToSort = propertyNameToSort; 
            } 
            #region IComparer<ListingCatalogItem> Members 
     
            public int Compare(ListingCatalogItem x, ListingCatalogItem y) 
            { 
                ListingInfoProp FromCompare = x.ListProperties.FirstOrDefault(o => o.Name == _propertyNameToSort.Name); 
                ListingInfoProp ToCompare = y.ListProperties.FirstOrDefault(o => o.Name == _propertyNameToSort.Name); 
                if (FromCompare != null && ToCompare == null
                    return 1; 
                else if (FromCompare == null && ToCompare != null
                    return -1; 
                else if (FromCompare == null && ToCompare == null || FromCompare.Value == ToCompare.Value) 
                    return 0; 
                switch (_propertyNameToSort.ItemDataType) 
                { 
                    case ItemDataType.BigInteger: 
                        return long.Parse(FromCompare.Value).CompareTo(long.Parse(ToCompare.Value)); 
                    case ItemDataType.Boolean: 
                        return Boolean.Parse(FromCompare.Value).CompareTo(Boolean.Parse(ToCompare.Value)); 
                    case ItemDataType.Currency: 
                        return Decimal.Parse(FromCompare.Value).CompareTo(Decimal.Parse(ToCompare.Value)); 
                    case ItemDataType.DateTime: 
                        return DateTime.Parse(FromCompare.Value).CompareTo(DateTime.Parse(ToCompare.Value)); 
                    case ItemDataType.Double: 
                        return Double.Parse(FromCompare.Value).CompareTo(Double.Parse(ToCompare.Value)); 
                    case ItemDataType.Float: 
                        return float.Parse(FromCompare.Value).CompareTo(float.Parse(ToCompare.Value)); 
                    case ItemDataType.Integer: 
                        return int.Parse(FromCompare.Value).CompareTo(int.Parse(ToCompare.Value)); 
                    default
                        return FromCompare.Value.CompareTo(ToCompare.Value); 
     
                } 
            } 
            #endregion 
        } 
        public static class InfoPropExtensions 
        { 
            public static object GetTypedValue(this ListingInfoProp b, InfoPropSchema schemaProperty) 
            { 
                if (b == null
                    return ""
                switch (schemaProperty.ItemDataType) 
                { 
                    case ItemDataType.Boolean: 
                        return String.IsNullOrEmpty(b.Value) ? false : Boolean.Parse(b.Value); 
                    case ItemDataType.String: 
                        return b.Value; 
                    default
                        return b.Value; 
                } 
            } 
        } 
     
        internal class ListPropriete : IValueConverter 
        { 
            private InfoPropSchema schemaProperty { getset; } 
            public ListPropriete(InfoPropSchema _schemaProperty) 
            { 
                schemaProperty = _schemaProperty; 
            } 
            #region IValueConverter Members 
     
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
            { 
                if (value is ObservableCollection<ListingInfoProp> && parameter != null && parameter is string
                { 
                    string tmp = (string)parameter; 
                    return (value as ObservableCollection<ListingInfoProp>).FirstOrDefault(o => o.Name == tmp).GetTypedValue(schemaProperty); 
     
                } 
                else 
                { 
                    return value; 
                } 
            } 
     
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
            { 
                return ""
            } 
            #endregion 
        } 
     




    When i sort by context menu, all works fine.
    But i want to use the same hability by clicking on header.
    So,
    i tried to manage that in Sorting Event, but when i set the new Sorting State, it seem to be lost, have you an idea ?

    I don't want to use the custom DataTable you provided (http://blogs.telerik.com/blogs/posts/09-04-23/lightweight_datatable_for_your_silverlight_applications.aspx and http://blogs.telerik.com/blogs/Libraries/Vladimir_Enchev/SilverlightDataTable_Q3_2009_SP2.sflb?download=true is broken),
    because i need to have the possibility to loadrowdetails without loading and have context menu action on each element (like modify and other), and if i haven't the id column, i cannot retrieve the value.

    Thank you.


  2. Vlad
    Admin
    Vlad avatar
    11100 posts

    Posted 05 Mar 2010 Link to this post

    Hi ,

    You can set SortingState similar to this demo:
    http://demos.telerik.com/silverlight/#GridView/Performance/ServerSide

    I've just checked our updated version of the DataTable however the download link works fine:
    http://blogs.telerik.com/Libraries/Vladimir_Enchev/SilverlightDataTable_Q3_2009_SP2.sflb?download=true

    Regards,
    Vlad
    the Telerik team

    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
  3. Ludovic Alcala
    Ludovic Alcala avatar
    24 posts
    Member since:
    Jan 2010

    Posted 05 Mar 2010 Link to this post

    Hello,
    thank you for your response.

    But i set the sorting state, and i after the return of method "Sorting", it seem be lost.

    Any idea ?

    Thank you.
Back to Top