如何编写 DataTrigger 以在鼠标悬停或弹出 IsOpen 时在 DataGrid 中显示过滤器图标?
How to write DataTrigger to Visible the Filter Icon in the DataGrid While on Mouse Hover or Popup IsOpen?
如何在 DataGrid 中设置过滤器图标,它应该在 MouseOver 和过滤器弹出窗口 IsOpen 上可见,否则会折叠。
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.
我需要在相应列的鼠标悬停事件上显示 (Visibility:Visible
) 过滤器图标按钮,或者如果用户可以单击过滤器图标按钮,则过滤器弹出窗口将打开,此时图标应该show - 过滤弹出 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 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>
**使用自定义行为解决整个问题**
创建一个新的 sub-classed 按钮 DataGridColHeaderButton。
我们需要这个 class 有两个主要原因:
a) 区分普通按钮和column-header按钮。
b) 访问弹出窗口以显示它。
创建 2 个独立的行为,即; ShowPopupBehavior, ShowHideFilterIconBehavior.
在 ViewModel 中引入一个新的 CLR/DP 属性 PopupFilter。由于 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;
}
}
ShowHideFilterIconBehavior.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 中的行为 **
现在我们也可以像处理标准行为一样附加这些行为。
为此,我们的行为需要无参数(默认)构造函数。
然后,我们不需要在 DataGridColHeaderButton 中使用与行为相关的属性,就像我们在代码中附加这些行为时必须做的那样。
在XAML中附加这些行为意味着我们可以随时将它们注释掉。
<local:DataGridColHeaderButton ...>
<i:Interaction.Behaviors>
<local:ShowHideFilterIconBehavior />
<local:ShowPopupBehavior />
</i:Interaction.Behaviors>
...
</local:DataGridColHeaderButton>
在此我将按钮命名为 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
});
}
}
多值转换器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
}
此转换器 return 为真 IsMouseHover
是 True
或 FilterButtonHashCode
属性 的值与 Button.GetHashCode()
匹配。基于这个简单的布尔return多值转换器与多个转换器参数,我们可以在没有C#行为的情况下实现上述任务
如何在 DataGrid 中设置过滤器图标,它应该在 MouseOver 和过滤器弹出窗口 IsOpen 上可见,否则会折叠。
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.
我需要在相应列的鼠标悬停事件上显示 (Visibility:Visible
) 过滤器图标按钮,或者如果用户可以单击过滤器图标按钮,则过滤器弹出窗口将打开,此时图标应该show - 过滤弹出 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 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>
**使用自定义行为解决整个问题**
创建一个新的 sub-classed 按钮 DataGridColHeaderButton。 我们需要这个 class 有两个主要原因: a) 区分普通按钮和column-header按钮。 b) 访问弹出窗口以显示它。
创建 2 个独立的行为,即; ShowPopupBehavior, ShowHideFilterIconBehavior.
在 ViewModel 中引入一个新的 CLR/DP 属性 PopupFilter。由于 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;
}
}
ShowHideFilterIconBehavior.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 中的行为 **
现在我们也可以像处理标准行为一样附加这些行为。
为此,我们的行为需要无参数(默认)构造函数。
然后,我们不需要在 DataGridColHeaderButton 中使用与行为相关的属性,就像我们在代码中附加这些行为时必须做的那样。
在XAML中附加这些行为意味着我们可以随时将它们注释掉。
<local:DataGridColHeaderButton ...> <i:Interaction.Behaviors> <local:ShowHideFilterIconBehavior /> <local:ShowPopupBehavior /> </i:Interaction.Behaviors> ... </local:DataGridColHeaderButton>
在此我将按钮命名为 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
});
}
}
多值转换器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
}
此转换器 return 为真 IsMouseHover
是 True
或 FilterButtonHashCode
属性 的值与 Button.GetHashCode()
匹配。基于这个简单的布尔return多值转换器与多个转换器参数,我们可以在没有C#行为的情况下实现上述任务