RadGridView Filter row - Add a Clear Filter button into the Filter textboxs

7 posts, 0 answers
  1. Sintayehu
    Sintayehu avatar
    67 posts
    Member since:
    Jan 2013

    Posted 06 Jun 2013 Link to this post

    Hi,

    In the RadGridView Filtering in the Filter Row Mode. I am trying to add a "filter clear button" in to the Filtering TextBoxes. I know I may have to add this new clear button into the StringFilterEditorTemplate and also figure out a way to add it to the dynamically generated TextBox. (please see my snippet showing where I maybe able to tap in to this). My main question here is is there a way to do this and Bind it to the ClearFilter method. I prefer this is all done from XAML and maybe an attached behavior.

    Please share if you have an example.


    Thanks!



    /* For the StringFilterEditorTemplate */

    <ControlTemplate x:Key="StringFilterEditorTemplate" TargetType="Editors:StringFilterEditor">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <telerik:RadToggleButton Style="{StaticResource RadToggleButtonFilterStyle}" Content="aA" Grid.Column="1" IsChecked="{Binding IsCaseSensitive, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="-3,0,0,0" Visibility="{Binding MatchCaseVisibility, RelativeSource={RelativeSource TemplatedParent}}" >
                        <ToolTipService.ToolTip>
                            <ToolTip telerik:LocalizationManager.ResourceKey="GridViewFilterMatchCase" />
                        </ToolTipService.ToolTip>
                    </telerik:RadToggleButton>
                    <TextBox Grid.Column="0" Text="{Binding Text, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" telerik:TextBoxBehavior.UpdateTextOnEnter="True" />
                </Grid>
        </ControlTemplate>       



    /* For the Dynamically generated TextBoxes*/
    private void OnFieldFilterEditorCreated(object sender, EditorCreatedEventArgs e)
            {
                var filterTextBox = e.Editor as TextBox;
                if (filterTextBox != null)
                {
                   filterTextBox.Style = (Style)Application.Current.Resources["TextBoxStyle"]; 




  2. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 07 Jun 2013 Link to this post

    Hello,

    There is a way to achieve this but it will involve a lot of hacks.

    Clearing the filter is not particularly related to the concrete type of field filter editor, i.e. StringFilterEditor (for strings), RadDateTimePicker (for DateTimes), TextBox (for everything else) so it might be a good idea to place this button next to and not inside the field filter editor.

    Here is the ControlTemplate of the entire control which you see in the header cell:

    <ControlTemplate x:Key="FieldFilterControlTemplate" TargetType="grid:FieldFilterControl">
        <Border BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="{TemplateBinding BorderThickness}">
            <Grid x:Name="PART_MainGrid">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <ContentControl x:Name="PART_FilterEditorContentControl"
                            Grid.Column="0"
                            IsEnabled="{Binding EditorIsEnabled}"
                            HorizontalContentAlignment="Stretch"
                            VerticalContentAlignment="Stretch" Margin="2 1 0 2"/>
     
                <telerik:RadDropDownButton x:Name="PART_DropDownButton"
                                       Grid.Column="1"
                                       KeepOpen="False" Style="{StaticResource FieldFilterDropDownButtonStyle}"
                                       DropDownIndicatorVisibility="Collapsed">
                    <Border Cursor="Hand" Background="Transparent" Padding="3 0 0 0">
                        <Grid Width="12" Height="13" Cursor="Hand">
                            <Path Fill="{StaticResource GridView_FilterIconOuterBorder}" Stretch="Fill" Margin="0 1 0 0" Data="M5,9 L6,9 6,10 5,10 z M4,4 L5,4 5,5 5,6 5,7 5,8 5,9 4,9 4,8 4,7 4,6 4,5 z M7.9850001,3 L8.985,3 8.985,4 8,4 8,5 8,6 8,7 8,8 8,9 8,10 8,11 7.9999997,12 6.9999998,12 6.9999998,11 6,11 6,10 6.9999999,10 6.9999999,9 6.9999999,8 6.9999999,7 6.9999999,6 6.9999999,5 6.9999999,4 7.9850001,4 z M3,3 L4,3 4,4 3,4 z M9,2 L10,2 10,3 9,3 z M2,2 L3,2 3,3 2,3 z M7.9999999,0 L9,0 10,0 11,0 12,0 12,1 11,1 11,2 10,2 10,1 9,1 7.9999999,1 z M0,0 L1,0 2,0 3,0 4,0 5,0 6,0 6.9999998,0 7.9999997,0 7.9999997,1 6.9999998,1 6,1 5,1 4,1 3,1 2,1 2,2 1,2 1,1 0,1 z"/>
                            <Path Fill="{StaticResource GridView_FilterIconTopBorder}" Stretch="Fill" Margin="2 1 2 0" VerticalAlignment="Top" Height="1" Data="M0,0 L1,0 2,0 3.0000002,0 4.0000002,0 5.0000001,0 5.9850001,0 6.0000001,0 6.9850001,0 7.9850001,0 7.9850001,1 6.9850001,1 6.0000001,1 5.9850001,1 5.0000001,1 4.0000002,1 3.0000002,1 2,1 1,1 0,1 z"/>
                            <Path Fill="{StaticResource GridView_FilterIconBackground}" Stretch="Fill" Margin="3 2 3 3" Data="M0,0 L1,0 2,0 3,0 4,0 5,0 6,0 6,1 5,1 4.985,1 4.985,2 4,2 4,3 4,4 4,5 4,6 4,7 4,8 3,8 3,7 2,7 2,6 2,5 2,4 2,3 2,2 1,2 1,1 0,1 z" />
                            <Path Fill="{StaticResource GridView_FilterIconBackground_Filtered}" Visibility="{Binding FunnelFillVisibility}" Stretch="Fill" Margin="3,2,3,3" Data="M0,0 L1,0 2,0 3,0 4,0 5,0 6,0 6,1 5,1 4.985,1 4.985,2 4,2 4,3 4,4 4,5 4,6 4,7 4,8 3,8 3,7 2,7 2,6 2,5 2,4 2,3 2,2 1,2 1,1 0,1 z" />
                            <Path Fill="{StaticResource GridView_FilterIconInnerBorder}" Stretch="Fill" Margin="0 0 0 1" Data="M5,9 L6,9 6,10 5,10 z M4,4 L5,4 5,5 5,6 5,7 5,8 5,9 4,9 4,8 4,7 4,6 4,5 z M7.9850001,3 L8.985,3 8.985,4 8,4 8,5 8,6 8,7 8,8 8,9 8,10 8,11 7.9999997,12 6.9999998,12 6.9999998,11 6,11 6,10 6.9999999,10 6.9999999,9 6.9999999,8 6.9999999,7 6.9999999,6 6.9999999,5 6.9999999,4 7.9850001,4 z M3,3 L4,3 4,4 3,4 z M9,2 L10,2 10,3 9,3 z M2,2 L3,2 3,3 2,3 z M7.9999999,0 L9,0 10,0 11,0 12,0 12,1 11,1 11,2 10,2 10,1 9,1 7.9999999,1 z M0,0 L1,0 2,0 3,0 4,0 5,0 6,0 6.9999998,0 7.9999997,0 7.9999997,1 6.9999998,1 6,1 5,1 4,1 3,1 2,1 2,2 1,2 1,1 0,1 z"/>
                        </Grid>
                    </Border>
                    <telerik:RadDropDownButton.DropDownContent>
                        <ListBox x:Name="PART_FilterOperatorsListBox"
                                 ItemsSource="{Binding AvailableOperatorViewModels}"
                                 SelectedItem="{Binding SelectedOperatorViewModel, Mode=TwoWay}"
                                 telerik:StyleManager.Theme="{StaticResource Theme}"/>
                    </telerik:RadDropDownButton.DropDownContent>
                </telerik:RadDropDownButton>
            </Grid>
        </Border>
    </ControlTemplate>

    Now, the empty ContentControl that you see in yellow called PART_FilterEditorContentControl is the placeholder where the appropriate editor is created and inserted at runtime. The RadDropDownButton in orange is the funnel on the right of it.

    You can place a button somewhere, for example between the two, i.e. create another ColumnDefinition.

    The DataContext of this FieldFilterControl is a view model called FieldFilterControlViewModel. This view model has a public collection called AvailableOperatorViewModels. This, as you can see above, is the ItemsSource of the ListBox showing the available operators. The first of them is a dummy operator, i.e. it is not an operator, but issues the clear command. As you can see, the SelectedItem of the ListBox is bound to another property on the view model called SelectedOperatorViewModel

    So your task is to simulate the user opening the drop-down and selecting the first choice, which is the pseudo-dummy-operator for Clearing the filters. So when the button is clicked, you can do something like this:

    var viewModel = ((FieldFilterControlViewModel)button.DataContext);

    viewModel.SelectedOperatorViewModel = viewModel.AvailableOperatorViewModels.First();

    This should simulate the use selecting the first item from the list box of available operators, which is the one that issues the clear logic.

    The view model has a method called ClearFilter but unfortunately it is private and cannot be used by you. That is why such hacks need to be employed. If you think that you can easily bind your custom clear button to a method on the view model, we can make this method public for the next Latest Internal Build.

    Another possible approach for clearing the filter would be to set the Value property of the view model to FilterDescriptor.UnsetValue, which means that the filter is not active, i.e. there is no filter. The Value property is the thing that user enters in the respective editor, i.e. the value that should be filtered with. Setting this to FilterDescriptor.UnsetValue has the same effect as clearing the filter, i.e. the user deleting all the text from the editor.

    Note that I have not tried all this I explained above, but it should work. However, this approach involves so many hacks that I cannot recommend it and cannot give any warranties about any side effects it might have. I am posting the source code of the view model for your reference as well:

    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Linq;
    using System.Windows;
    using Telerik.Windows.Data;
     
    namespace Telerik.Windows.Controls.GridView
    {
        /// <summary>
        /// This is for internal use only and is not intended to be used directly from your code.
        /// </summary>
        public sealed class FieldFilterControlViewModel : ViewModelBase
        {
            internal const string GridViewClearFilter = "GridViewClearFilter";
            internal const string GridViewFilterIsTrue = "GridViewFilterIsTrue";
            internal const string GridViewFilterIsFalse = "GridViewFilterIsFalse";
     
            private IFilterableColumn column;
            private OperatorValueFilterDescriptorBase filterDescriptor;
     
            private readonly IList<FilterOperatorViewModel> availableOperatorViewModels = new List<FilterOperatorViewModel>();
            private FilterOperatorViewModel selectedOperatorViewModel;
            private FilterOperator? defaultOperator;
            private object valueField = FilterDescriptor.UnsetValue;
            private bool isCaseSensitive;
            private INotifyCollectionChanged targetFilters;
     
            /// <summary>
            /// Gets the available filter operators.
            /// </summary>
            /// <value>The available filter operators.</value>
            public IEnumerable<FilterOperatorViewModel> AvailableOperatorViewModels
            {
                get
                {
                    return this.availableOperatorViewModels;
                }
            }
     
            private void PopulateAvailableFilterOperatorViewModels()
            {
                var args = this.column.CallFilterOperatorsLoading();
     
                this.defaultOperator = args.DefaultOperator1;
     
                // This is the "Clear Filter" fake operator.
                this.availableOperatorViewModels.Add(new FilterOperatorViewModel(GridViewClearFilter));
     
                // Boolean columns do not have editors, but use fake filter operators.
                if (this.IsBooleanFilter)
                {
                    args.AvailableOperators.Remove(FilterOperator.IsEqualTo);
                    args.AvailableOperators.Remove(FilterOperator.IsNotEqualTo);
     
                    this.availableOperatorViewModels.Add(new FilterOperatorViewModel(GridViewFilterIsTrue, FilterOperator.IsEqualTo));
                    this.availableOperatorViewModels.Add(new FilterOperatorViewModel(GridViewFilterIsFalse, FilterOperator.IsEqualTo));
     
                    // This should never change from here on.
                    this.defaultOperator = FilterOperator.IsEqualTo;
                }
     
                // Finally, yield the "normal", non-fake operators.
                foreach (var filterOperator in args.AvailableOperators)
                {
                    this.availableOperatorViewModels.Add(new FilterOperatorViewModel(filterOperator));
                }
            }
     
            private bool IsBooleanFilter
            {
                get
                {
                    return this.column.EffectiveFilteringType == typeof(bool) ||
                           this.column.EffectiveFilteringType == typeof(bool?);
                }
            }
     
            /// <summary>
            /// Gets or sets the selected filter operator.
            /// </summary>
            /// <value>The selected filter operator.</value>
            public FilterOperatorViewModel SelectedOperatorViewModel
            {
                get
                {
                    return this.selectedOperatorViewModel;
                }
                set
                {
                    if (this.selectedOperatorViewModel != value)
                    {
                        this.selectedOperatorViewModel = value;
                        this.OnSelectedOperatorViewModelChanged();
                        this.RefreshEditorIsEnabled();
                        this.OnPropertyChanged("SelectedOperatorViewModel");
                    }
                }
            }
     
            private void OnSelectedOperatorViewModelChanged()
            {
                if (this.SelectedOperatorViewModel != null)
                {
                    if (this.SelectedOperatorViewModel.IsReal)
                    {
                        // The user has selected a "real" FilterOperator.
                        this.ApplyFilter();
                    }
                    else
                    {
                        switch (this.SelectedOperatorViewModel.LocalizationKey)
                        {
                            case GridViewClearFilter:
                                // The use has selected the "Clear" dummy filter operator.
                                this.ClearFilter();
                                break;
                            case GridViewFilterIsTrue:
                                this.SetFilterDescriptorOperatorToIsEqualToNoCallback();
                                this.Value = true;
                                break;
                            case GridViewFilterIsFalse:
                                this.SetFilterDescriptorOperatorToIsEqualToNoCallback();
                                this.Value = false;
                                break;
                        }
                    }
                }
            }
     
            private void SetFilterDescriptorOperatorToIsEqualToNoCallback()
            {
                this.filterDescriptor.PropertyChanged -= this.OnFilterDescriptorPropertyChanged;
                this.filterDescriptor.Operator = FilterOperator.IsEqualTo;
                this.filterDescriptor.PropertyChanged += this.OnFilterDescriptorPropertyChanged;
            }
     
            private void RefreshEditorIsEnabled()
            {
                FilterOperator? selectedOperator = this.SelectedOperatorViewModel.FilterOperator.GetValueOrDefault();
     
                this.EditorIsEnabled = selectedOperator.HasValue && !selectedOperator.Value.IsUnary();
            }
     
            private bool editorIsEnabled;
     
            /// <summary>
            /// Gets or sets a value indicating whether [editor is enabled].
            /// </summary>
            /// <value><c>true</c> if [editor is enabled]; otherwise, <c>false</c>.</value>
            public bool EditorIsEnabled
            {
                get
                {
                    return this.editorIsEnabled;
                }
                private set
                {
                    if (this.editorIsEnabled != value)
                    {
                        this.editorIsEnabled = value;
                        this.OnPropertyChanged("EditorIsEnabled");
                    }
                }
            }
     
            private void SyncSelectedOperatorViewModelFieldWithFilterDescriptorOperator()
            {
                if (this.IsBooleanFilter)
                {
                    if (object.Equals(this.filterDescriptor.Value, true))
                    {
                        this.selectedOperatorViewModel = this.AvailableOperatorViewModels
                                                             .SingleOrDefault(vm => vm.LocalizationKey == GridViewFilterIsTrue);
                    }
                    else if (object.Equals(this.filterDescriptor.Value, false))
                    {
                        this.selectedOperatorViewModel = this.AvailableOperatorViewModels
                                                             .SingleOrDefault(vm => vm.LocalizationKey == GridViewFilterIsFalse);
                    }
                    else if (object.Equals(this.filterDescriptor.Value, OperatorValueFilterDescriptorBase.UnsetValue))
                    {
                        this.selectedOperatorViewModel = this.AvailableOperatorViewModels
                                                             .SingleOrDefault(vm => vm.LocalizationKey == GridViewClearFilter);
                    }
                }
                else
                {
                    var realSelectedOperatorViewModel = this.AvailableOperatorViewModels
                                                            .SingleOrDefault(vm => vm.IsReal && vm.FilterOperator == this.filterDescriptor.Operator);
     
                    if (realSelectedOperatorViewModel != null)
                    {
                        this.selectedOperatorViewModel = realSelectedOperatorViewModel;
                    }
                    else
                    {
                        this.selectedOperatorViewModel = this.AvailableOperatorViewModels
                                                             .SingleOrDefault(vm => vm.LocalizationKey == GridViewClearFilter);
                    }
                }
     
                this.OnPropertyChanged("SelectedOperatorViewModel");
            }
     
            /// <summary>
            /// Gets or sets the value.
            /// </summary>
            /// <value>The value.</value>
            public object Value
            {
                get
                {
                    return this.valueField;
                }
                set
                {
                    if (this.valueField != value)
                    {
                        if (value == OperatorValueFilterDescriptorBase.UnsetValue)
                        {
                            this.valueField = OperatorValueFilterDescriptorBase.UnsetValue;
                        }
                        else if (this.filterDescriptor.DataType == null)
                        {
                            // We do not know the MemberType so we cannot convert anything.
                            this.valueField = value;
                        }
                        else if (FilterDescriptorViewModel.IsNullOrAnEmptyString(value))
                        {
                            // TODO: Change the above with null only when we create a way
                            // to have the StringFilterEditor assign null instead of string.Empty.
                            if (this.filterDescriptor.DataType.IsValueType &&
                                !this.filterDescriptor.DataType.IsNullableType())
                            {
                                this.valueField = FilterDescriptor.UnsetValue;
                            }
                            else
                            {
                                this.valueField = null;
                            }
                        }
                        else if (value.GetType().IsCompatibleWith(this.filterDescriptor.DataType))
                        {
                            this.valueField = value;
                        }
                        else if (this.filterDescriptor.DataType.IsNumericType() && value.GetType().IsNumericType())
                        {
                            this.valueField = value;
                        }
                        else
                        {
                            object convertedValue;
                            var success = TypeExtensions.TryConvert(value,
                                this.filterDescriptor.DataType,
                                out convertedValue);
     
                            if (success)
                            {
                                this.valueField = convertedValue;
                            }
                            else
                            {
                                // This will display a validation tooltip which will be localized.
                                var message = LocalizationManager.GetString("FilterEditorFormatExceptionMessage");
                                throw new FormatException(message);
                            }
                        }
     
                        this.ApplyFilter();
                        this.RefreshFunnelFillVisibility();
                        this.OnPropertyChanged("Value");
                    }
                }
            }
     
            /// <summary>
            /// Gets or sets a value indicating whether this instance is case sensitive.
            /// </summary>
            /// <value>
            ///     <c>true</c> if this instance is case sensitive; otherwise, <c>false</c>.
            /// </value>
            public bool IsCaseSensitive
            {
                get
                {
                    return this.isCaseSensitive;
                }
                set
                {
                    if (this.isCaseSensitive != value)
                    {
                        this.isCaseSensitive = value;
                        this.ApplyFilter();
                        this.OnPropertyChanged("IsCaseSensitive");
                    }
                }
            }
     
            private Visibility funnelFillVisibility;
     
            /// <summary>
            /// This is for internal use only and is not intended to be used directly from your code.
            /// </summary>
            public Visibility FunnelFillVisibility
            {
                get
                {
                    return this.funnelFillVisibility;
                }
                set
                {
                    if (this.funnelFillVisibility != value)
                    {
                        this.funnelFillVisibility = value;
                        this.OnPropertyChanged("FunnelFillVisibility");
                    }
                }
            }
     
            private void RefreshFunnelFillVisibility()
            {
                this.FunnelFillVisibility = this.IsActive ? Visibility.Visible : Visibility.Collapsed;
            }
     
            private bool IsActive
            {
                get
                {
                    return this.filterDescriptor.IsActive &&
                           this.column.TargetFilters.Contains(this.column.ColumnFilterDescriptor);
                }
            }
     
            /// <summary>
            /// Initializes a new instance of the <see cref="FieldFilterControlViewModel" /> class. This is for internal use only and is not intended to be used directly from your code.
            /// </summary>
            internal FieldFilterControlViewModel(IFilterableColumn column)
            {
                this.column = column;
                this.filterDescriptor = this.column.ColumnFilterDescriptor.FieldFilter.Filter1;
     
                this.valueField = this.filterDescriptor.Value;
                this.isCaseSensitive = this.filterDescriptor.IsCaseSensitive;
                this.PopulateAvailableFilterOperatorViewModels();
                this.InitializeDefaultFilterOperator();
                this.RefreshFunnelFillVisibility();
                this.RefreshEditorIsEnabled();
     
                this.filterDescriptor.PropertyChanged += this.OnFilterDescriptorPropertyChanged;
     
                this.targetFilters = this.column.TargetFilters;
                this.targetFilters.CollectionChanged += this.OnTargetFiltersCollectionChanged;
            }
     
            internal void InitializeDefaultFilterOperator()
            {
                var op = this.CalculateDefaultOperator();
     
                if (op != null)
                {
                    this.filterDescriptor.Operator = op.Value;
                    this.SyncSelectedOperatorViewModelFieldWithFilterDescriptorOperator();
                }
                else
                {
                    this.selectedOperatorViewModel = this.AvailableOperatorViewModels
                                                         .SingleOrDefault(vm => vm.LocalizationKey == GridViewClearFilter);
                    this.OnPropertyChanged("SelectedOperatorViewModel");
                }
            }
     
            /// <inheritdoc />
            protected override void Dispose(bool disposing)
            {
                if (disposing)
                {
                    if (this.filterDescriptor != null)
                    {
                        this.filterDescriptor.PropertyChanged -= this.OnFilterDescriptorPropertyChanged;
                        this.filterDescriptor = null;
                    }
     
                    if (this.targetFilters != null)
                    {
                        this.targetFilters.CollectionChanged -= this.OnTargetFiltersCollectionChanged;
                        this.targetFilters = null;
                    }
     
                    this.selectedOperatorViewModel = null;
                    this.defaultOperator = null;
                    this.valueField = null;
                    this.column = null;
                }
     
                base.Dispose(disposing);
            }
     
            private void OnFilterDescriptorPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                this.valueField = this.filterDescriptor.Value;
                this.OnPropertyChanged("Value");
     
                this.isCaseSensitive = this.filterDescriptor.IsCaseSensitive;
                this.OnPropertyChanged("IsCaseSensitive");
     
                this.SyncSelectedOperatorViewModelFieldWithFilterDescriptorOperator();
     
                this.RefreshEditorIsEnabled();
                this.RefreshFunnelFillVisibility();
            }
     
            private void OnTargetFiltersCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                this.RefreshEditorIsEnabled();
                this.RefreshFunnelFillVisibility();
            }
     
            private FilterOperator? CalculateDefaultOperator()
            {
                if (this.IsActive)
                {
                    return this.filterDescriptor.Operator;
                }
     
                if (this.defaultOperator.HasValue)
                {
                    return this.defaultOperator.Value;
                }
     
                return null;
            }
     
            private void ClearFilter()
            {
                var filtersToRemove = new List<IFilterDescriptor>();
     
                if (this.filterDescriptor.IsActive)
                {
                    filtersToRemove.Add(this.CreateCopyOfActual());
                }
     
                if (filtersToRemove.Count > 0)
                {
                    if (this.CallFiltering(Enumerable.Empty<IFilterDescriptor>(), filtersToRemove))
                    {
                        // Nothing to do since the event was cancelled.
                        return;
                    }
     
                    // This will first remove the ColumnFilterDescriptor from TargetFilters
                    // causing a single CollectionChanged and will then clear it when it is
                    // no longer part of TargetFilters.
                    this.filterDescriptor.PropertyChanged -= this.OnFilterDescriptorPropertyChanged;
                    this.column.ClearFilters();
                    this.filterDescriptor.PropertyChanged += this.OnFilterDescriptorPropertyChanged;
                }
     
                Debug.Assert(this.filterDescriptor.Value == OperatorValueFilterDescriptorBase.UnsetValue, "UnsetValue");
                this.InitializeDefaultFilterOperator();
                this.RefreshEditorIsEnabled();
     
                this.Value = OperatorValueFilterDescriptorBase.UnsetValue;
                this.IsCaseSensitive = false;
     
                if (filtersToRemove.Count > 0)
                {
                    this.CallFiltered(Enumerable.Empty<IFilterDescriptor>(), filtersToRemove);
                }
     
                this.OnPropertyChanged("FunnelFillVisibility");
            }
     
            private void ApplyFilter()
            {
                if (this.SelectedOperatorViewModel == null || !this.SelectedOperatorViewModel.FilterOperator.HasValue)
                {
                    return;
                }
     
                var addedFilters = new List<IFilterDescriptor>();
                var removedFilters = new List<IFilterDescriptor>();
     
                if (this.HasChanges)
                {
                    if (this.filterDescriptor.IsActive)
                    {
                        removedFilters.Add(this.filterDescriptor.Copy());
                    }
     
                    var actual = this.CreateCopyOfActual();
     
                    if (actual.IsActive)
                    {
                        addedFilters.Add(actual);
                    }
                }
     
                if (addedFilters.Count == 0 && removedFilters.Count == 0)
                {
                    // Nothing to do since nothing has changed.
                    return;
                }
     
                if (this.CallFiltering(addedFilters, removedFilters))
                {
                    this.RejectChanges();
                }
                else
                {
                    // Filtering has not been cancelled and has to be applied.
                    // We want to make the changes in a single batch so we suspend any notifications.
                    this.column.ColumnFilterDescriptor.SuspendNotifications();
     
                    if (this.HasChanges)
                    {
                        this.AcceptChanges();
                    }
     
                    // Let the grid know that something has changed.
                    this.column.ColumnFilterDescriptor.ResumeNotifications();
     
                    this.CallFiltered(addedFilters, removedFilters);
                }
            }
     
            private bool CallFiltering(IEnumerable<IFilterDescriptor> added, IEnumerable<IFilterDescriptor> removed)
            {
                var args = this.column.CallFiltering(added, removed);
                return args.Cancel;
            }
     
            private void CallFiltered(IEnumerable<IFilterDescriptor> added, IEnumerable<IFilterDescriptor> removed)
            {
                this.column.CallFiltered(added, removed);
            }
     
            internal bool HasChanges
            {
                get
                {
                    return
                          this.filterDescriptor.Operator != this.SelectedOperatorViewModel.FilterOperator.GetValueOrDefault() ||
                          this.filterDescriptor.Value != this.Value ||
                          this.filterDescriptor.IsCaseSensitive != this.IsCaseSensitive;
                }
            }
     
            internal OperatorValueFilterDescriptorBase CreateCopyOfActual()
            {
                var copyOfActual = this.filterDescriptor.Copy();
     
                if (this.SelectedOperatorViewModel.IsReal)
                {
                    copyOfActual.Operator = this.SelectedOperatorViewModel.FilterOperator.Value;
                }
     
                copyOfActual.Value = this.Value;
     
                copyOfActual.IsCaseSensitive = this.IsCaseSensitive;
     
                return copyOfActual;
            }
     
            internal void AcceptChanges()
            {
                this.filterDescriptor.PropertyChanged -= this.OnFilterDescriptorPropertyChanged;
     
                this.filterDescriptor.Operator = this.SelectedOperatorViewModel.FilterOperator.Value;
                this.filterDescriptor.Value = this.Value;
                this.filterDescriptor.IsCaseSensitive = this.IsCaseSensitive;
     
                this.filterDescriptor.PropertyChanged += this.OnFilterDescriptorPropertyChanged;
            }
     
            internal void RejectChanges()
            {
                this.SyncSelectedOperatorViewModelFieldWithFilterDescriptorOperator();
                this.Value = this.filterDescriptor.Value;
                this.IsCaseSensitive = this.filterDescriptor.IsCaseSensitive;
            }
        }
    }

    I hope that this information can give you a start in exploring the different options that you have and experiment.
    Regards,
    Rossen Hristov
    Telerik

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  3. Sintayehu
    Sintayehu avatar
    67 posts
    Member since:
    Jan 2013

    Posted 07 Jun 2013 Link to this post

    Great I gave it a try and it works fine so far. Thanks!!


    As you indicated I created a third column and added a Button. I created a TriggerAction class to do the actuall clearing and from my Style file using an interaction trigger I Trigger on the click event.

    Here is the snippet :

    <ControlTemplate x:Key="FieldFilterControlTemplate" TargetType="telerik:FieldFilterControl">
         <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
          <Grid x:Name="PART_MainGrid">
           <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="50"/>
           </Grid.ColumnDefinitions>
           <ContentControl x:Name="PART_FilterEditorContentControl" Grid.Column="0" HorizontalContentAlignment="Stretch" IsEnabled="{Binding EditorIsEnabled}" Margin="2,1,0,2" VerticalContentAlignment="Stretch" Style="{StaticResource ContentControlStyleFilter}"/>

                    <Button Content="Clear" Grid.Column="1">
    <i:Interaction.Triggers>
    <i:EventTrigger EventName="Click" >
    <local:GridFilterClearAction />
    </i:EventTrigger>
    </i:Interaction.Triggers>
    </Button>


           <telerik:RadDropDownButton x:Name="PART_DropDownButton" Grid.Column="2" DropDownIndicatorVisibility="Collapsed" KeepOpen="False" Style="{StaticResource FieldFilterDropDownButtonStyle}" >
            <telerik:RadDropDownButton.DropDownContent>
             <ListBox x:Name="PART_FilterOperatorsListBox" ItemsSource="{Binding AvailableOperatorViewModels}" SelectedItem="{Binding SelectedOperatorViewModel, Mode=TwoWay}" Style="{StaticResource ListBoxStyleGridFilter}" />
            </telerik:RadDropDownButton.DropDownContent>
            <Border Background="Transparent" Cursor="Hand" Padding="0,0,1,0">
             <Grid Cursor="Hand" Height="13" Width="12">
              <Path Data="M5,9 L6,9 6,10 5,10 z M4,4 L5,4 5,5 5,6 5,7 5,8 5,9 4,9 4,8 4,7 4,6 4,5 z M7.9850001,3 L8.985,3 8.985,4 8,4 8,5 8,6 8,7 8,8 8,9 8,10 8,11 7.9999997,12 6.9999998,12 6.9999998,11 6,11 6,10 6.9999999,10 6.9999999,9 6.9999999,8 6.9999999,7 6.9999999,6 6.9999999,5 6.9999999,4 7.9850001,4&#xa; z M3,3 L4,3 4,4 3,4 z M9,2 L10,2 10,3 9,3 z M2,2 L3,2 3,3 2,3 z M7.9999999,0 L9,0 10,0 11,0 12,0 12,1 11,1 11,2 10,2 10,1 9,1 7.9999999,1 z M0,0 L1,0 2,0 3,0 4,0 5,0 6,0 6.9999998,0 7.9999997,0 7.9999997,1 6.9999998,1 6,1 5,1 4,1 3,1 2,1 2,2 1,2 1,1 0,1 z" Fill="{StaticResource GridView_FilterIconOuterBorder}" Margin="0,1,0,0" Stretch="Fill"/>
              <Path Data="M0,0 L1,0 2,0 3.0000002,0 4.0000002,0 5.0000001,0 5.9850001,0 6.0000001,0 6.9850001,0 7.9850001,0 7.9850001,1 6.9850001,1 6.0000001,1 5.9850001,1 5.0000001,1 4.0000002,1 3.0000002,1 2,1 1,1 0,1 z" Fill="{StaticResource GridView_FilterIconTopBorder}" Height="1" Margin="2,1,2,0" Stretch="Fill" VerticalAlignment="Top"/>
              <Path Data="M0,0 L1,0 2,0 3,0 4,0 5,0 6,0 6,1 5,1 4.985,1 4.985,2 4,2 4,3 4,4 4,5 4,6 4,7 4,8 3,8 3,7 2,7 2,6 2,5 2,4&#xa;2,3 2,2 1,2 1,1 0,1 z" Fill="{StaticResource GridView_FilterIconBackground}" Margin="3,2,3,3" Stretch="Fill"/>
              <Path Data="M0,0 L1,0 2,0 3,0 4,0 5,0 6,0 6,1 5,1 4.985,1 4.985,2 4,2 4,3 4,4 4,5 4,6 4,7 4,8 3,8 3,7 2,7 2,6 2,5 2,4&#xa;2,3 2,2 1,2 1,1 0,1 z" Fill="{StaticResource GridView_FilterIconBackground_Filtered}" Margin="3,2,3,3" Stretch="Fill" Visibility="{Binding FunnelFillVisibility}"/>
              <Path Data="M5,9 L6,9 6,10 5,10 z M4,4 L5,4 5,5 5,6 5,7 5,8 5,9 4,9 4,8 4,7 4,6 4,5 z M7.9850001,3 L8.985,3 8.985,4 8,4 8,5 8,6 8,7 8,8 8,9 8,10 8,11 7.9999997,12 6.9999998,12 6.9999998,11 6,11 6,10 6.9999999,10 6.9999999,9 6.9999999,8 6.9999999,7 6.9999999,6 6.9999999,5 6.9999999,4 7.9850001,4&#xa; z M3,3 L4,3 4,4 3,4 z M9,2 L10,2 10,3 9,3 z M2,2 L3,2 3,3 2,3 z M7.9999999,0 L9,0 10,0 11,0 12,0 12,1 11,1 11,2 10,2 10,1 9,1 7.9999999,1 z M0,0 L1,0 2,0 3,0 4,0 5,0 6,0 6.9999998,0 7.9999997,0 7.9999997,1 6.9999998,1 6,1 5,1 4,1 3,1 2,1 2,2 1,2 1,1 0,1 z" Fill="{StaticResource GridView_FilterIconInnerBorder}" Margin="0,0,0,1" Stretch="Fill"/>
             </Grid>
            </Border>
           </telerik:RadDropDownButton>              
                    
          </Grid>
         </Border>
        </ControlTemplate>


    -----TriggerAction Class ----


    using System.Linq;
    using System.Windows.Controls;
    using System.Windows.Interactivity;
    using Telerik.Windows.Controls.GridView;

    namespace somenamespace
    {

        public class GridFilterClearAction : TriggerAction<Button>
        {
          
            protected override void Invoke(object parameter)
            {
                if (AssociatedObject == null)
                    return;

                if (AssociatedObject is Button)
                {
                    var button = AssociatedObject;
                    var viewModel = ((FieldFilterControlViewModel)button.DataContext);

                    viewModel.SelectedOperatorViewModel = viewModel.AvailableOperatorViewModels.First();
     
                }
            }
        }
    }

  4. Sintayehu
    Sintayehu avatar
    67 posts
    Member since:
    Jan 2013

    Posted 07 Jun 2013 Link to this post

    On a similar subject I would like to add Icons Next to the Operators. Example if it is Greater than " > ". And also when an operator is selected I would like to change the Funnel Icon that triggers the drop down to be the Selected operator Icon. This is to give the user a visual indication of what operator is being used currently.

    Seems to me that the ItemSources in the ListBox below should already contain

    the operators with the icons.

    <
    ListBox x:Name="PART_FilterOperatorsListBox" ItemsSource="{Binding AvailableOperatorViewModels}" SelectedItem="{Binding SelectedOperatorViewModel, Mode=TwoWay}" Style="{StaticResource ListBoxStyleGridFilter}" />

    I hoped to do this by adding new operators OnFilterOperatorsLoading with icons from code into the AvailableOperators but that is a RemoveOnlyCollection.

    Let me know if this is somehow achivable.

    Thanks!

  5. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 10 Jun 2013 Link to this post

    Hello,

    I am afraid that we do not have any icons for the operators and we never had ones. You might need to define a custom ItemTemplate for the ListBox and provide operator icons of your own.

    Regards,
    Rossen Hristov
    Telerik

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  6. Sintayehu
    Sintayehu avatar
    67 posts
    Member since:
    Jan 2013

    Posted 10 Jun 2013 Link to this post

    Providing my own ItemTemplate sounds good but I have some questions,

    1 - Isn't an item template templating one single Item? if so how can I use it to template the 15 available items?
            -- My goal is to have an icon per operator

    2 - Even if I could somehow do this What are the Binding Properties of the Operators?

    3 - Would templating an item somehow also template the Selected Item? Because my goal is when user selects an item I would like to replace the Funnel dropdown icon with the selected operator icon, to give user a visual cue.

    Thanks for your help.


       <ListBox x:Name="PART_FilterOperatorsListBox" ItemsSource="{Binding AvailableOperatorViewModels}" SelectedItem="{Binding SelectedOperatorViewModel, Mode=TwoWay}" Style="{StaticResource ListBoxStyleGridFilter}">
                               
         <ListBox.ItemTemplate>
                                    <DataTemplate>
                                        <StackPanel Orientation="Horizontal">
                                            <Ellipse Fill="Aqua" Width="10" Height="7"></Ellipse>
                                            <TextBlock Text="{Binding ???}"/>
                                        </StackPanel>
                                    </DataTemplate>
            </ListBox.ItemTemplate>

    </ListBox>
  7. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 11 Jun 2013 Link to this post

    Hello,

    1) Please, read this article before going on.

    You can create an item template which contains your SL image. The data context of each list box item will be the respective FilterOperatorViewModel instance. The FilterOperatorViewModel has a property called FilterOperator which returns the actual FilterOperator enum value.

    Now, you can data bind the source of your SL image to the FilterOperator property with an IValueConverter. This IValueConverter will accept the FilterOperator enum value and return the respective icon or path to the image or you get the idea. This is up to you. This topic however goes way beyond the scope of Telerik support since this is general Silverlight know-how, i.e. data binding, images, converters and so on.

    Something like this in pseudo-code:

    <ListBox.ItemTemplate>
                                    <DataTemplate>
                                            <Image Source="{Binding FilterOperator, Converter=<<your converter that accepts a filter operator and return an image or path>>}"/>
                                    </DataTemplate>
    </ListBox.ItemTemplate>

    Here is the source code of the FilterOperatorViewModel  class:

    using Telerik.Windows.Data;
     
    namespace Telerik.Windows.Controls.GridView
    {
        /// <summary>
        /// This is for internal use only and is not intended to be used directly from your code.
        /// </summary>
        public sealed class FilterOperatorViewModel
        {
            private readonly FilterOperator? filterOperator = null;
     
            internal FilterOperatorViewModel(string localizationKey)
            {
                this.LocalizationKey = localizationKey;
            }
     
            internal FilterOperatorViewModel(string localizationKey, FilterOperator filterOperator)
            {
                // This constructor is for IsTrue and IsNotTrue
                this.LocalizationKey = localizationKey;
                this.filterOperator = filterOperator;
            }
     
            internal FilterOperatorViewModel(FilterOperator filterOperator)
            {
                this.IsReal = true;
                this.LocalizationKey = string.Format("GridViewFilter{0}", filterOperator.ToString());
                this.filterOperator = filterOperator;
            }
     
            internal bool IsReal { get; private set; }
     
            internal string LocalizationKey { get; private set; }
     
            /// <summary>
            /// Gets the filter operator.
            /// </summary>
            /// <value>The filter operator.</value>
            public FilterOperator? FilterOperator
            {
                get
                {
                    return this.filterOperator;
                }
            }
     
            /// <inheritdoc />
            public override string ToString()
            {
                return LocalizationManager.GetString(this.LocalizationKey);
            }
        }
    }


    2) Simply bind the thing in your item template to the FilterOperator property. Remember that the DataContext of the thing in the item template is an instance of the FilterOperatorViewModel class, which has a single property called FilterOperator.

    3) I really don't think that this is possible. The funnel that you see is the Path inside the PART_DropDownButton. I don't think that you can easily change that. Let us know if you manage to invent a way to do that.

    Please, note that I have provided all the default XAML that is relevant and all relevant view model classes, which by the way you can easily find in the source code yourself. How you customize all of this XAML from here on would really be up to you and really falls beyond the scope of Telerik-specific support. If you are having difficulties with this process, you can always count on our Enterprise Services.

    I hope this helps.

    Regards,
    Rossen Hristov
    Telerik

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

Back to Top