Search code examples
wpffilterdatagriddatatrigger

How to write DataTrigger to Visible the Filter Icon in the DataGrid While on Mouse Hover or Popup IsOpen?


How to Set Filter Icon in the DataGrid, it should be Visible on MouseOver and Filter Popup IsOpen otherwise Collapsed.

Note:

Design the Datagrid in one XAML and the Filter Popup should be in Main View XAML, The DataGrid XAML inherits the Main View XAML.

The Filter Icon is a Button designed in app.xaml and call the Style in the DataGrid.

I need to show (Visibility:Visible) the Filter Icon Button while on Mouse Hover Event of the Corresponding Column or If user can click the Filter Icon Button then the Filter Popup gets opened and that time the Icon should show - Filter Popup IsOpen=True state. The Filter Icon Button should Collapsed while on Popup gets closed while on Icon Button Clicked otherwise Mouse Hover is not happened.

Main View XAML : Popup Source Code

<Popup Name="popFilter" Placement="Mouse" StaysOpen="False" Width="200" IsOpen="{Binding IsPopupFilterOpen, Mode=TwoWay}">
    <Border Background="White" BorderBrush="Gray" BorderThickness="1,1,1,1">
        <StackPanel Margin="5,5,5,15">
            <TextBlock Text="Welcome to Popup Window" />
        </StackPanel>
    </Border>
</Popup>

Child View XAML : DataGrid

<DataGrid Name="EmpList" ColumnHeaderStyle="{StaticResource FilterDataGridColumnHeader}" AutoGenerateColumns="False" ItemsSource="{Binding EmpList}">
   <DataGrid.Columns>
       <DataGridTextColumn Binding="{Binding Name}" Header="Employee Name" ElementStyle="{StaticResource DataGridElementStyle}" />
       <DataGridTextColumn Binding="{Binding Age}" Header="Employee Age" ElementStyle="{StaticResource DataGridElementStyle}" />
   </DataGrid.Columns>
</DataGrid>

Filter Icon Button : App.xaml

<Application.Resources>
    <Style TargetType="{x:Type DataGridColumnHeader}" x:Key="FilterDataGridColumnHeader">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
                    <Button Grid.Column="2" Command="{Binding Path=DataContext.PopUpCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" Style="{StaticResource TransButtonStyleKey}">
                        <Button.CommandParameter>
                            <MultiBinding Converter="{StaticResource MultiValueConverterKey}">
                                <Binding RelativeSource="{ RelativeSource Mode=FindAncestor, AncestorType={x:Type cust:DataGrid}}" />
                                <Binding Path="Column" RelativeSource="{ RelativeSource Mode=TemplatedParent}" />
                            </MultiBinding>
                        </Button.CommandParameter>
                        <ContentControl Name="autofilter" Visibility="Collapsed"  ContentTemplate="{StaticResource FilterButtonStyleKey}"  Margin="0 0 3 0"></ContentControl>
                    </Button>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Application.Resources>

FilterButtonStyleKey :

<DataTemplate x:Key="FilterButtonStyleKey">
    <Canvas Height="15.898" Width="15.297" HorizontalAlignment="Center" VerticalAlignment="Center" Background="Transparent">
        <Path Data="M16.0117,6.7368C18.3417,6.7368,20.6727,6.7358,23.0027,6.7378C23.5327,6.7378,23.5977,6.8308,23.6437,7.3438C23.7027,7.9958,23.4897,8.4748,23.0197,8.9548C21.4107,10.5968,19.8547,12.2888,18.2957,13.9788C18.1647,14.1208,18.1137,14.3828,18.1117,14.5898C18.0987,17.0608,18.1067,19.5308,18.0907,22.0018C18.0887,22.2158,18.0077,22.4968,17.8607,22.6158C17.7697,22.6878,17.4587,22.5408,17.2807,22.4368C16.3057,21.8718,15.3447,21.2788,14.3677,20.7148C14.0637,20.5408,13.9287,20.3278,13.9297,19.9728C13.9407,18.1778,13.9257,16.3848,13.9357,14.5908C13.9367,14.2698,13.8367,14.0388,13.6137,13.8058C12.1347,12.2548,10.6717,10.6898,9.2027,9.1298C9.0967,9.0168,8.9927,8.9018,8.8797,8.7958C8.4137,8.3608,8.2387,7.6118,8.4377,7.0158C8.5277,6.7478,8.7137,6.7358,8.9347,6.7368C10.0937,6.7388,11.2517,6.7378,12.4097,6.7378C13.6107,6.7378,14.8107,6.7378,16.0117,6.7368z" Height="16.898" Canvas.Left="-0.5" StrokeStartLineCap="Round" Stretch="Fill" StrokeEndLineCap="Round" Stroke="#FF323232" StrokeThickness="1" StrokeLineJoin="Round" Canvas.Top="-0.5" Width="16.297"/>
        <Path Data="M14.2427,14.3921L17.9117,14.3921" Height="1" Canvas.Left="5.386" StrokeStartLineCap="Round" Stretch="Fill" StrokeEndLineCap="Round" Stroke="#FF323232" StrokeThickness="1" StrokeLineJoin="Round" Canvas.Top="7.156" Width="4.669"/>
    </Canvas>
</DataTemplate>

Solution

  • In this I named the Button as x:Name="autoFilterBtn" I added one more Command Parameter <Binding RelativeSource="{RelativeSource Mode=Self}"/> within the Button Command.

    Filter Icon Button : App.xaml

    <Application.Resources>
        <Style TargetType="{x:Type DataGridColumnHeader}" x:Key="FilterDataGridColumnHeader">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
                        <Button x:Name="autoFilterBtn" Grid.Column="2" Command="{Binding Path=DataContext.PopUpCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" Style="{StaticResource TransButtonStyleKey}">
                            <Button.CommandParameter>
                                <MultiBinding Converter="{StaticResource MultiValueConverterKey}">
                                    <Binding RelativeSource="{ RelativeSource Mode=FindAncestor, AncestorType={x:Type cust:DataGrid}}" />
                                    <Binding Path="Column" RelativeSource="{ RelativeSource Mode=TemplatedParent}" />
                                    <Binding RelativeSource="{RelativeSource Mode=Self}"/>
                                </MultiBinding>
                            </Button.CommandParameter>
                            <ContentControl Name="autofilter" Visibility="Collapsed"  ContentTemplate="{StaticResource FilterButtonStyleKey}"  Margin="0 0 3 0"></ContentControl>
                        </Button>
                        <ControlTemplate.Triggers>
                        <DataTrigger Value="True">
                            <DataTrigger.Binding>
                                <MultiBinding Converter="{StaticResource FilterVisibilityCheckConverter}">
                                    <Binding Path="IsMouseOver" RelativeSource="{RelativeSource Self}" />
                                    <Binding Path="DataContext.FilterButtonHashCode" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}" />
                                    <Binding ElementName="autoFilterBtn" />
                                </MultiBinding>
                            </DataTrigger.Binding>
                            <Setter TargetName="autofilter" Property="Visibility" Value="Visible"/>
                        </DataTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Application.Resources>
    

    At the time of PopUpCommand Command execution I updated the int Property FilterButtonHashCode

    private Button _filterButton = new Button();
    public Button FilterButton
    {
        get { return _filterButton; }
        set
        {
            _filterButton = value;
            OnPropertyChanged();
        }
    }
    
    private int _filterButtonHashCode = 0;
    public int FilterButtonHashCode
    {
        get { return _filterButtonHashCode; }
        set
        {
            _filterButtonHashCode = value;
            OnPropertyChanged();
        }
    }
    
    private bool _isPopupFilterOpen = false;
    public bool IsPopupFilterOpen
    {
        get { return _isPopupFilterOpen; }
        set
        {
            _isPopupFilterOpen = value;
            if (value == false)
                FilterButtonHashCode = 0;
            OnPropertyChanged();
        }
    }
    
    public ICommand FilterPopUpCommand
    {
        get
        {
            return new DelegatingCommand((param) =>
            {
                object[] obj = param as object[];
                FilterButton = obj[2] as Button;
                FilterButtonHashCode = FilterButton.GetHashCode();
    
                // Logic to Show Filter Popup
    
            });
        }
    }
    

    MultiValue Converter Class:

    public class FilterVisibilityCheckConverter : IMultiValueConverter
    {
        #region IMultiValueConverter Members
    
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool isMouseHover = false;
            int hasCode = 0;
            Button filterButton = new Button();
    
            if ((values[0] ?? false) is bool)
            {
                isMouseHover = bool.Parse((values[0] ?? false).ToString());
            }
    
            if (values[1] is int)
            {
                hasCode = int.Parse((values[1] ?? "0").ToString());
            }
    
            if (values[2] is Button)
            {
                filterButton = values[2] as Button;
            }
    
            if (values != null && values.Length == 3 && values[0] != null && values[1] != null && values[2] != null && ((isMouseHover == true) || (hasCode == filterButton.GetHashCode())))
            {
                return true;
            }
            else
                return false;
        }
    
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    
        #endregion
    }
    

    This Converter returns true IsMouseHover is True OR the value of the FilterButtonHashCode property matches with the Button.GetHashCode(). Based on this simple Boolean return Multivalue Converter with Multiple Converter Parameter, we can achieve the above task without C# Behaviors