Как написать DataTrigger, чтобы значок фильтра в DataGrid был виден при наведении курсора мыши или всплывающем окне IsOpen?

Как установить значок фильтра в DataGrid, он должен быть видимым при наведении курсора мыши и всплывающем окне фильтра IsOpen, в противном случае он должен быть свернут.

Примечание:

Разработайте Datagrid в одном XAML, и всплывающее окно фильтра должно быть в XAML основного представления. XAML DataGrid наследует XAML основного представления.

Значок фильтра - это кнопка, созданная в app.xaml и вызывающая стиль в DataGrid.

Мне нужно показать (Visibility:Visible) кнопку со значком фильтра при наведении курсора мыши на соответствующий столбец или если пользователь может щелкнуть кнопку со значком фильтра, открывается всплывающее окно фильтра, и в этот раз должен отображаться значок - состояние всплывающего окна фильтра IsOpen=True. Кнопка со значком фильтра должна сворачиваться, когда всплывающее окно закрывается при нажатии кнопки со значком, в противном случае наведение курсора мыши не происходит.

Основной вид XAML: исходный код всплывающего окна

<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>

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>

Кнопка значка фильтра: 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>

person B.Balamanigandan    schedule 17.12.2015    source источник
comment
Можете ли вы показать код, который вы пробовали до сих пор?   -  person user1672994    schedule 17.12.2015
comment
@ user1672994 - Исходный код я выложил. Пожалуйста, помогите мне.   -  person B.Balamanigandan    schedule 17.12.2015
comment
@ B.Balamanigandan Также, пожалуйста, разместите FilterButtonStyleKey.   -  person AnjumSKhan    schedule 17.12.2015
comment
@AnjumSKhan Я разместил FilterButtonStyleKey, любезно помогите мне.   -  person B.Balamanigandan    schedule 17.12.2015
comment
@ B.Balamanigandan Опубликованный подход работает, как ожидалось, с одним недостатком, т.е. PopUp теперь присутствует на каждой кнопке. Будем работать над этим вопросом сейчас.   -  person AnjumSKhan    schedule 17.12.2015


Ответы (2)


** Решение всей проблемы с помощью настраиваемого поведения **

  1. Создайте новую кнопку подкласса DataGridColHeaderButton. Нам нужен этот класс по двум основным причинам: а) Чтобы различать обычную кнопку и кнопку заголовка столбца. б) Чтобы иметь доступ к всплывающему окну для его отображения.

  2. Создайте 2 отдельных поведения, а именно; ShowPopupBehavior, ShowHideFilterIconBehavior.

  3. Представьте новое свойство PopupFilter среды CLR / DP в ViewModel. Поскольку Popup присутствует в нашей ViewModel, и мы хотим, чтобы это Popup достигало наших специальных кнопок, которые присутствуют в Style. Мы сделаем это с помощью привязки.

     public MainWindow()
        {
            InitializeComponent();           
    
            /* new clr property */
            PopupFilter = popFilter;
            this.DataContext = this;            
        }
    

Наш стиль выглядит так, как показано ниже. Обратите внимание на привязку и замените Button на DataGridColHeaderButton в исходном стиле.

<Style x:Key="FilterDataGridColumnHeader" ...>
...
 <local:DataGridColHeaderButton PopupToShow="{Binding PopupFilter, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}">
   <local:DataGridColHeaderButton.Content>
   ...
   </local:DataGridColHeaderButton.Content>
 </local:DataGridColHeaderButton>
...
</Style>

DataGridColHeaderButton.cs

public class DataGridColHeaderButton : Button
    {
        // Using a DependencyProperty as the backing store for PopupToShow.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PopupToShowProperty =
            DependencyProperty.Register("PopupToShow", typeof(Popup), typeof(DataGridColHeaderButton), new PropertyMetadata(null));    

        public Popup PopupToShow
        {
            get { return (Popup)GetValue(PopupToShowProperty); }
            set { SetValue(PopupToShowProperty, value); }
        }

        public ShowPopupBehavior popupBehavior { get; set; }
        public ShowHideFilterIconBehavior showHideBehavior { get; set; }

        public DataGridColHeaderButton()
        {            
            popupBehavior = new ShowPopupBehavior(this);
            showHideBehavior = new ShowHideFilterIconBehavior(this);
        }
    }

ShowPopupBehavior.cs

public class ShowPopupBehavior:Behavior<DataGridColHeaderButton>
{
    Popup popup;

    public ShowPopupBehavior(DataGridColHeaderButton btn)
    {
        this.Attach(btn);           
    }

    protected override void OnAttached()
    {
        AssociatedObject.Loaded += AssociatedObject_Loaded;
        AssociatedObject.Click += AssociatedObject_Click;            
        base.OnAttached();
    }

    void AssociatedObject_Click(object sender, RoutedEventArgs e)
    {
        AssociatedObject.PopupToShow.IsOpen = true;
        ContentControl autofilter = (ContentControl)VisualTreeHelper.GetChild(((Grid)(AssociatedObject.Content)), 1);
        autofilter.Visibility = Visibility.Visible;
        popup.PlacementTarget = AssociatedObject;
    }

    void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        popup = AssociatedObject.PopupToShow;
        popup.Closed += popup_Closed;
    }

    void popup_Closed(object sender, EventArgs e)
    {
        ContentControl autofilter = (ContentControl)VisualTreeHelper.GetChild(((Grid)(AssociatedObject.Content)), 1);
        autofilter.Visibility = Visibility.Collapsed;
    }       
}

ПоказатьHideFilterIconBehavior.cs

public class ShowHideFilterIconBehavior : Behavior<DataGridColHeaderButton>
{
    public ShowHideFilterIconBehavior(DataGridColHeaderButton btn)
    {
        this.Attach(btn);
    }

    protected override void OnAttached()
    {
        AssociatedObject.MouseEnter += AssociatedObject_MouseEnter;
        AssociatedObject.MouseLeave += AssociatedObject_MouseLeave;
        base.OnAttached();
    }

    void AssociatedObject_MouseLeave(object sender, MouseEventArgs e)
    {
        ContentControl autofilter = (ContentControl)VisualTreeHelper.GetChild(((Grid)(AssociatedObject.Content)), 1);
        autofilter.Visibility = Visibility.Collapsed;
    }

    void AssociatedObject_MouseEnter(object sender, MouseEventArgs e)
    {
        ContentControl autofilter = (ContentControl)VisualTreeHelper.GetChild(((Grid)(AssociatedObject.Content)), 1);
        autofilter.Visibility = Visibility.Visible;
    }
}

** Использование поведения в XAML **

  1. Теперь мы также можем привязать эти поведения, как и к стандартным.

  2. Для этого нам нужны конструкторы без параметров (по умолчанию) в нашем поведении.

  3. Тогда нам не нужны свойства, связанные с поведением, в нашем DataGridColHeaderButton, как мы должны делать при присоединении этих поведений в коде.

  4. Присоединение этих поведений к XAML означает, что мы можем комментировать их в любое время.

     <local:DataGridColHeaderButton ...>
        <i:Interaction.Behaviors>
           <local:ShowHideFilterIconBehavior />
           <local:ShowPopupBehavior />    
        </i:Interaction.Behaviors>
        ...
     </local:DataGridColHeaderButton>
    

Посмотреть результат

person AnjumSKhan    schedule 17.12.2015
comment
Всплывающее окно находится в родительском представлении не в том же представлении, это общий элемент управления, который я использую везде, где хочу, в моем проекте. - person B.Balamanigandan; 17.12.2015
comment
@ B.Balamanigandan привет, почти готово, без кода очень сложно. - person AnjumSKhan; 17.12.2015
comment
@ B.Balamanigandan привет, готово. проверьте плз, спросите, есть ли сомнения. - person AnjumSKhan; 17.12.2015
comment
Большое спасибо AnjumSKhan. Завтра утром я интегрирую этот код в свой основной проект. - person B.Balamanigandan; 17.12.2015
comment
@ B.Balamanigandan Обновлено относительно того, как прикрепить эти поведения в xaml. - person AnjumSKhan; 17.12.2015

В этом случае я назвал кнопку x:Name="autoFilterBtn". Я добавил еще один параметр команды <Binding RelativeSource="{RelativeSource Mode=Self}"/> в команду кнопки.

Кнопка значка фильтра: 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>

Во время выполнения PopUpCommand Команды я обновил свойство int 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:

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
}

Этот конвертер возвращает true IsMouseHover is True ИЛИ значение свойства FilterButtonHashCode совпадает с Button.GetHashCode(). На основе этого простого многозначного преобразователя логического возврата с несколькими параметрами преобразователя мы можем выполнить указанную выше задачу без поведения C #

person B.Balamanigandan    schedule 08.02.2016