Home Forums WPF controls Xceed DataGrid for WPF Alternate rows to visually group values

Viewing 7 posts - 1 through 7 (of 7 total)
  • Author
    Posts
  • obiben
    Participant
    Post count: 28
    #44365 |

    Hi there,

    I’ve seen the posts about the IndexToOddConverter, but how would one go about alternating row styles to “group” values together? In my case I need to visually group bids together by price, without using the “actual grouping” functionality.

    Thanks
    Benoit

    Fawzi [Xceed]
    Member
    Post count: 722

    Hi,

    I am not sure what do you mean by: “visually group bids together by price, without using the “actual grouping” functionality”. What do you mean by without using group functionality? Are you looking to set the row’s background, of the bids column, based on its price without grouping at all?

    obiben
    Participant
    Post count: 28

    Oh wow I didn’t sign up for updates!

    Hi Fawzi,

    This is what I mean by visually grouping:
    Desired visual grouping

    “Actual grouping” refers to the grouping functionality in xceed where you drag a header and the grid groups data entries together under a header.

    I instead need to group entries via a background color. Headers would take up too much space, mostly since many entries are alone in their group.

    obiben
    Participant
    Post count: 28

    Just to be clear: the screenshot isn’t of my solution. I still haven’t found a way to do what I need to.

    obiben
    Participant
    Post count: 28

    For eventual desperate googlers:

    I was pointed towards the GroupConfigurationSelector, which could be used like this:
    dataGrid.GroupConfigurationSelector = new PriceHighlighter(priceCollection);

    This can worked, but the grouping functionality impacted loading times for me, and added work to hide group header lines.

    The same thing exists for individual rows, however, and works wonders:

    dataGrid.ItemContainerStyleSelector = new PriceHighLighter(priceCollection);

    The highlighter, in my case, works like this:

        class PriceHighlighter : StyleSelector
        {
            BookOrders _Orders; //collection of PriceInfo objects
            public PriceHighlighter(BookOrders orders)
            {
                _Orders = orders;
            }
    
            public override Style SelectStyle(object item, DependencyObject container)
            {
                PriceInfo info = item as PriceInfo;
    
                List<decimal> prices = _Orders.Select(o => o.Price).Distinct().OrderBy(o => o).ToList();
                Style style = new Style(typeof(Xceed.Wpf.DataGrid.DataRow));
    
                int index = prices.IndexOf(info.Price);
                if (index % 2 == 1) 
                    style.Setters.Add(new Setter(DataRow.BackgroundProperty, new SolidColorBrush(Color.FromArgb(0x99, 0x99, 0x99, 0xcc))));
    
                return style;
            }
        }

    I can then have visually grouped prices without actually computing the groups:
    Grouped rows!

    obiben
    Participant
    Post count: 28

    Aaaand nope.

    My solution works until things start changing, then you realize the styles never get reapplied.

    Is it possible to trigger a StyleSelector refresh?

    obiben
    Participant
    Post count: 28

    I’ve changed approaches, since the styles seems they won’t be reselected, ever, unless I empty the grid and repopulate it, which isn’t smooth at all.

    Instead I went with a converter and some additional properties. For performance reasons, I’ve added a property List<OrderInfo> Prices to my collection class, that gets invalidated whenever a collection change occurs, and is recomputed only on demand, and only when invalidated:

    
            List<decimal> _Prices = null;
            public List<decimal> Prices
            {
                get
                {
                    return _Prices ?? (_Prices = this.Select(o => o.Price).Distinct().OrderBy(o=>o).ToList());
                }
            }
    

    Then I’ve given access to the parent collection to every member of that collection:

    
            BookOrders _Parent;
    
            public int Index
            {
                get
                {
                    return _Parent.Prices.IndexOf(Price);
                }
            }
    
            public OrderInfoVM(OrderInfo order, BookOrders parent)
            {
                _Inner = order;
                _Parent = parent;
                _Parent.CollectionChanged += OnParentChanged;
            }
    
            ~OrderInfoVM()
            {
                _Parent.CollectionChanged -= OnParentChanged;
            }
    
            private void OnParentChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                OnPropertyChanged("Index");
            }
    

    Then a simple converter can tell us whether this is an “odd line” or not…

    
        [ValueConversion(typeof(int), typeof(bool))]
        public class IndexToOddConverter : IValueConverter
        {
            public static IndexToOddConverter Singleton
            {
                get
                {
                    if (singleton == null)
                        singleton = new IndexToOddConverter();
    
                    return singleton;
                }
            }
    
            private static IndexToOddConverter singleton;
    
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                if ((!targetType.IsAssignableFrom(typeof(bool)))
                  || (value == null)
                  || (value.GetType() != typeof(int)))
                {
                    return DependencyProperty.UnsetValue;
                }
    
                int index = (int)value;
    
                return ((index % 2) == 1);
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                return Binding.DoNothing;
            }
    
            #endregion
        }
    
    

    And a style can use it:

    
                <xcdg:DataGridControl.Resources>
                    <Style TargetType="xcdg:DataRow">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Index, Converter={StaticResource IndexToOddConverter}}" Value="True">
                                <Setter Property="Background" Value="{StaticResource oddRowBrush}" />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </xcdg:DataGridControl.Resources>
    
Viewing 7 posts - 1 through 7 (of 7 total)
  • You must be logged in to reply to this topic.