Excel-like filtering pin position

8 posts, 1 answers
  1. Dominik
    Dominik avatar
    59 posts
    Member since:
    Dec 2012

    Posted 09 Jan 2015 Link to this post

    Hi,

    Is it possible to somehow change the position of the pin button (that open Excel-like filtering context menu), so it will be placed under the column header text?
    Check image: http://imgur.com/5WZu5UU
  2. Hristo Merdjanov
    Admin
    Hristo Merdjanov avatar
    711 posts

    Posted 14 Jan 2015 Link to this post

    Hi Dominik,

    Thank you for writing.

    Yes, it is possible to create a layout of GridHeaderCellElement with a filtering button similar to the one shown in your picture. To reach this visual appearance you would need to create a custom GridHeaderCellElement and override the logic for the setting the position of the StackLayout element containing the FilterButton. More information about the layout logic of Telerik Presentation Framework can be found here.

    Please check the code snippet below with my sample implementation:
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
              
            this.radGridView1.BestFitColumns(BestFitColumnMode.AllCells);
            this.radGridView1.EnableFiltering = true;
            this.radGridView1.MasterTemplate.ShowHeaderCellButtons = true;
            this.radGridView1.MasterTemplate.ShowFilteringRow = false;
        }
      
        private void radGridView1_CreateCell(object sender, GridViewCreateCellEventArgs e)
        {
            if (e.CellType == typeof(GridHeaderCellElement))
            {
                e.CellElement = new CustomGridHeaderCellElement(e.Column, e.Row);
            }
        }
      
        private void Form1_Load(object sender, EventArgs e)
        {
            this.productsTableAdapter.Fill(this.nwindDataSet.Products);
      
            radGridView1.MasterView.TableHeaderRow.Height = 100;
        }
    }


    public class CustomGridHeaderCellElement : GridHeaderCellElement
    {
        public CustomGridHeaderCellElement(GridViewColumn column, GridRowElement row)
            : base(column, row)
        {
        }
     
        protected override Type ThemeEffectiveType
        {
            get
            {
                return typeof(GridHeaderCellElement);
            }
        }
     
        private bool IsTextRightAligned()
        {
            if (
                ((this.TextAlignment == System.Drawing.ContentAlignment.MiddleRight ||
                this.TextAlignment == System.Drawing.ContentAlignment.TopRight ||
                this.TextAlignment == System.Drawing.ContentAlignment.BottomRight) && !this.RightToLeft)
                ||
                ((this.TextAlignment == System.Drawing.ContentAlignment.MiddleLeft ||
                this.TextAlignment == System.Drawing.ContentAlignment.TopLeft ||
                this.TextAlignment == System.Drawing.ContentAlignment.BottomLeft) && this.RightToLeft))
            {
                return true;
            }
     
            return false;
        }
     
        protected override SizeF ArrangeOverride(SizeF finalSize)
        {
            this.ArrowPosition = SetArrowPosition();
     
            RectangleF clientRect = GetClientRectangle(finalSize);
            float cellWidth = clientRect.Width;
     
            //arrange the text according to filter button (stack layout)
            if (this.StackLayout.Visibility == ElementVisibility.Visible && this.FilterButton.Visibility == ElementVisibility.Visible)
            {
                float diff = finalSize.Width - this.StackLayout.DesiredSize.Width - this.Layout.DesiredSize.Width;
     
                if (diff > 0 && !this.IsTextRightAligned())
                {
                    diff = this.StackLayout.DesiredSize.Width;
                }
                else
                {
                    diff = 0;
                }
     
                clientRect.Width -= this.StackLayout.DesiredSize.Width - diff;
     
                if (this.RightToLeft)
                {
                    clientRect.X += this.StackLayout.DesiredSize.Width - diff;
                }
            }
     
            if (this.ArrowPosition != ArrowPositionEnum.Top && this.ArrowPosition != ArrowPositionEnum.Bottom)
            {
                clientRect.Width -= 2 * this.Arrow.DesiredSize.Width + 2;
     
                if (this.RightToLeft)
                {
                    clientRect.X += 2 * this.Arrow.DesiredSize.Width + 2;
                }
            }
     
            this.Layout.Arrange(clientRect);
            foreach (RadElement element in this.Children)
            {
                if (element.Visibility == ElementVisibility.Collapsed)
                {
                    continue;
                }
                if (element == this.Arrow)
                {
                    if (!this.ViewTemplate.EnableSorting)
                    {
                        element.Visibility = ElementVisibility.Hidden;
                        continue;
                    }
     
                    //prevent an arrow from going into another column when the width is very small
                    if (finalSize.Width - 2 * this.Arrow.DesiredSize.Width > 0 && 2 * this.Arrow.DesiredSize.Width < finalSize.Width)
                    {
                        if (this.SortOrder != null && this.SortOrder != RadSortOrder.None && this.ColumnInfo.SortOrder != RadSortOrder.None)
                        {
                            element.Visibility = ElementVisibility.Visible;
                        }
     
                        ArrangeArrow(finalSize, element);
                    }
                    else
                    {
                        element.Visibility = ElementVisibility.Hidden;
                    }
                }
                else if (element == this.StackLayout)
                {
                    if (this.RightToLeft)
                    {
                        this.StackLayout.Arrange(new RectangleF(
                            0,
                            (finalSize.Height - this.StackLayout.DesiredSize.Height) / 2,
                            this.StackLayout.DesiredSize.Width, this.StackLayout.DesiredSize.Height
                            ));
                    }
                    else
                    {
                        this.StackLayout.Arrange(new RectangleF(
                            finalSize.Width / 2 - this.StackLayout.DesiredSize.Width / 2,
                            finalSize.Height / 2 + this.StackLayout.DesiredSize.Height / 2,
                            this.StackLayout.DesiredSize.Width, this.StackLayout.DesiredSize.Height
                            ));
                    }
                }
                else
                {
                    this.ArrangeElement(element, finalSize, clientRect);
                }
            }
     
     
            return finalSize;
        }
     
    }

    I am also sending you a screenshot showing how the grid looks on my side.

    I hope this information is useful. Should you have further questions please do not hesitate to write back.

    Regards,
    Hristo
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
  3. UI for WinForms is Visual Studio 2017 Ready
  4. Dominik
    Dominik avatar
    59 posts
    Member since:
    Dec 2012

    Posted 20 Jan 2015 in reply to Hristo Merdjanov Link to this post

    Thank you for the solution. It works well.

    However, I have another question.
    How in the filter row change the standard PopUp to Excel-like PopUp? 
    Check image: FilterPopUp
  5. Hristo Merdjanov
    Admin
    Hristo Merdjanov avatar
    711 posts

    Posted 22 Jan 2015 Link to this post

    Hi Dominik,

    Thank you for writing back.

    You could reach this type of drop down menu by subscribing to the ContextMenuOpening event and if the provider is GridFilterCellElement then create a new excel-like filter pop up. Please find my code example below:
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
     
            this.radGridView1.BestFitColumns(BestFitColumnMode.AllCells);
            this.radGridView1.EnableFiltering = true;
            this.radGridView1.MasterTemplate.ShowHeaderCellButtons = true;
            this.radGridView1.MasterTemplate.ShowFilteringRow = true;
        }
     
        private void radGridView1_CreateCell(object sender, GridViewCreateCellEventArgs e)
        {
            if (e.CellType == typeof(GridHeaderCellElement))
            {
                e.CellElement = new CustomGridHeaderCellElement(e.Column, e.Row);
            }
        }
     
        private void Form1_Load(object sender, EventArgs e)
        {
            this.productsTableAdapter.Fill(this.nwindDataSet.Products);
            radGridView1.MasterView.TableHeaderRow.Height = 50;
        }
     
        string columnName = string.Empty;
        private void radGridView1_ContextMenuOpening(object sender, ContextMenuOpeningEventArgs e)
        {
            GridFilterCellElement menuProvider = e.ContextMenuProvider as GridFilterCellElement;
            if (menuProvider != null)
            {
                e.Cancel = true;
                columnName = menuProvider.ColumnInfo.Name;
     
                IGridFilterPopup filterPopup = CreateFilterPopup(menuProvider);
                FieldInfo fi = this.radGridView1.TableElement.GetType().GetField("gridFilterPopup", BindingFlags.NonPublic | BindingFlags.Instance);
                fi.SetValue(this.radGridView1.TableElement, filterPopup);
                filterPopup.FilterConfirmed += filterPopup_FilterConfirmed;
                filterPopup.Show(Cursor.Position);
            }
        }
     
        private void filterPopup_FilterConfirmed(object sender, EventArgs e)
        {
            IGridFilterPopup filterPopup = (IGridFilterPopup)sender;
            filterPopup.FilterConfirmed -= filterPopup_FilterConfirmed;
     
     
            if (this.radGridView1.FilterDescriptors.Contains(columnName) && columnName != string.Empty)
            {
                this.radGridView1.MasterTemplate.EventDispatcher.SuspendEvent(EventDispatcher.FilterChangingEvent);
                this.radGridView1.MasterTemplate.EventDispatcher.SuspendEvent(EventDispatcher.FilterChangedEvent);
                this.radGridView1.FilterDescriptors.Remove(columnName);
                this.radGridView1.MasterTemplate.EventDispatcher.ResumeEvent(EventDispatcher.FilterChangingEvent);
                this.radGridView1.MasterTemplate.EventDispatcher.ResumeEvent(EventDispatcher.FilterChangedEvent);
            }
            if (filterPopup.FilterDescriptor != null)
            {
                filterPopup.FilterDescriptor.IsFilterEditor = true;
                this.radGridView1.FilterDescriptors.Add(filterPopup.FilterDescriptor);
                this.Focus();
            }
        }
     
        private IGridFilterPopup CreateFilterPopup(GridFilterCellElement cell)
        {
            BaseFilterPopup filterPopup = null;
     
            if (cell.ColumnInfo is GridViewDateTimeColumn)
            {
                filterPopup = new RadDateFilterPopup((GridViewDataColumn)cell.ColumnInfo);
            }
            else
            {
                filterPopup = new RadListFilterPopup((GridViewDataColumn)cell.ColumnInfo);
            }
     
            filterPopup.SetTheme(this.radGridView1.ThemeName);
            filterPopup.RightToLeft = cell.RightToLeft ? System.Windows.Forms.RightToLeft.Yes : System.Windows.Forms.RightToLeft.No;
            filterPopup.HorizontalPopupAlignment = cell.RightToLeft ? HorizontalPopupAlignment.RightToRight :
                                                                      HorizontalPopupAlignment.LeftToLeft;
     
            return filterPopup;
        }
    }

    I am also sending you a .gif file showing how the grid behaves on my side.

    I hope this helps. Should you have further questions please do not hesitate to write back.

    Regards,
    Hristo
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
  6. Dominik
    Dominik avatar
    59 posts
    Member since:
    Dec 2012

    Posted 23 Jan 2015 in reply to Hristo Merdjanov Link to this post

    Hi, 

    Thanks for the very professional answer.
    However, there is a problem with DateTime columns.

    In line:
    fi.SetValue(_DG.TableElement, filterPopup);

    Error:
    A first chance exception of type 'System.ArgumentException' occurred in mscorlib.dll
    Additional information: Object of type 'Telerik.WinControls.UI.RadDateFilterPopup' cannot be converted to type 'Telerik.WinControls.UI.IGridFilterPopupInteraction'.
  7. Answer
    Hristo Merdjanov
    Admin
    Hristo Merdjanov avatar
    711 posts

    Posted 27 Jan 2015 Link to this post

    Hello,

    Thank you for writing back.

    This exception is caused by the fact that the filter popup element of a GridViewDateTimeColumn does not implement the IGridFilterPopupInteraction interface which is actually the type of the field we are trying to set. With the following cast your application should not throw this exception anymore. Please see below:
    FieldInfo fi = this.radGridView1.TableElement.GetType().GetField("gridFilterPopup", BindingFlags.NonPublic | BindingFlags.Instance);
    fi.SetValue(this.radGridView1.TableElement, filterPopup as IGridFilterPopupInteraction);

    I hope this helps. Should you have further questions please do not hesitate to write back.

    Regards,
    Hristo Merdjanov
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
  8. Dominik
    Dominik avatar
    59 posts
    Member since:
    Dec 2012

    Posted 13 May 2015 in reply to Hristo Merdjanov Link to this post

    Thank you for the solution. It works well.
  9. Dominik
    Dominik avatar
    59 posts
    Member since:
    Dec 2012

    Posted 13 May 2015 in reply to Hristo Merdjanov Link to this post

    Thank you for the solution. It works well.
Back to Top
UI for WinForms is Visual Studio 2017 Ready