Chip 的 ListBox 和 DataTrigger 问题
Problem with ListBox and DataTrigger for Chip
我对 ListBoxItem
和 DataTrigger
有疑问。
当用鼠标单击芯片项目时,我想更改 Chip
项目的 Background
颜色。
我认为问题出在这行代码
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ListBoxItem},Path=IsSelected}"
Value="True">
<Setter Property="IconBackground"
Value="#1b5eb2" />
<Setter Property="Opacity"
Value="1"></Setter>
</DataTrigger>
运行 我的代码我得到了一个信号类别列表(如下面的屏幕截图所示):
但是,当我用鼠标点击它们时,圆圈的颜色没有改变。
它应该像这样工作(点击时):
我尝试了一些东西并检查了很多关于 DataTrigger
的主题,但我似乎无法弄清楚。
我的.xaml 观点
<ListBox Name="SignalCategories"
ItemsSource="{Binding DefinedSignalCategories}"
SelectionMode="Single"
HorizontalAlignment="Center"
VerticalAlignment="Top"
BorderThickness="0">
<!--changing default ListBoxItem to hide selection highlight-->
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<!--changing default orientation-->
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<!--custom view-->
<materialDesign:Chip Content="{Binding Name}"
Margin="5"
IconForeground="{DynamicResource PrimaryHueDarkForegroundBrush}">
<materialDesign:Chip.Style>
<Style TargetType="{x:Type materialDesign:Chip}">
<Setter Property="Opacity"
Value="0.85" />
<Setter Property="IconBackground"
Value="Gray"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Opacity"
Value="1" />
<Setter Property="IconBackground"
Value="#1b5eb2">
</Setter>
</Trigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ListBoxItem},Path=IsSelected}"
Value="True">
<Setter Property="IconBackground"
Value="#1b5eb2" />
<Setter Property="Opacity"
Value="1"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</materialDesign:Chip.Style>
<materialDesign:Chip.Icon>
<materialDesign:PackIcon Kind="{Binding IconName}" />
</materialDesign:Chip.Icon>
</materialDesign:Chip>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
我发现问题出在 materialDesign:Chip
上。
我在没有使用 materialDesign 的情况下重做了它,现在它可以正常工作了。
工作代码:
<ListBox.ItemTemplate>
<DataTemplate>
<!--custom view-->
<Grid Width="auto"
Height="30"
x:Name="grid1"
Margin="10">
<Border BorderBrush="Transparent"
HorizontalAlignment="Left"
Background="#939393"
Panel.ZIndex="1000"
BorderThickness="0"
CornerRadius="30"
Width="30"
Height="30"
x:Name="BorderCircle">
<materialDesign:PackIcon Kind="{Binding IconName}"
Margin="5"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Foreground="White" />
</Border>
<Border Background="#efefef"
BorderThickness="0"
CornerRadius="15"
HorizontalAlignment="Right"
Margin="10 0 0 0">
<TextBlock Text="{Binding Name}"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Margin="25 0 10 0" />
</Border>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}"
Value="True">
<Setter TargetName="BorderCircle"
Property="Background"
Value="#1b5eb2" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
输出:
这不起作用的原因是您误用了 Chip
控件。是一个类型derived from ButtonBase
, which means it is basically a button. It handles mouse click events, which sets the e.Handled
flag of the corresponding routed event arguments to true
. See The Concept of Handled供参考
The value of Handled affects how a routed event is reported or processed as it travels further along the route. If Handled
is true
in the event data for a routed event, then handlers that listen for that routed event on other elements are generally no longer invoked for that particular event instance.
因此,Chip
上的点击被 ListBoxItem
忽略,因此未被选中。您当然可以使用在 code-behind 中使用 handledEventsToo
注册点击处理程序的解决方法,如文章中所述,然后在可视化树中搜索 ListBoxItem
并设置 IsSelected
true
,但我不推荐它,因为首先使用它是错误的控件。由于 Chip
是一个按钮,因此它具有 Mouse Over 和 Pressed 的视觉状态以及您可以执行的其他状态和大量标记不需要也不必为了 使按钮表现得像不是按钮一样进行覆盖 。这没有意义。
你可以做的是 copy the essentials of the default style for Chip
并从中制作 DataTemplate
或自定义控件。以下数据模板应该适合您。
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.Resources>
<materialDesign:NullableToVisibilityConverter x:Key="NullableToVisibilityConverter" />
<materialDesign:PackIcon x:Key="Icon"
Kind="{Binding IconName}" />
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border CornerRadius="16"
Background="{DynamicResource MaterialDesignChipBackground}"
Grid.ColumnSpan="3" />
<ContentControl Grid.Column="0"
Content="{StaticResource Icon}"
Background="{DynamicResource PrimaryHueMidBrush}"
FontSize="17"
FontWeight="Regular"
IsTabStop="False"
Visibility="{Binding Source={StaticResource Icon}, Converter={StaticResource NullableToVisibilityConverter}}"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
Height="32"
Width="32">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Foreground" Value="{DynamicResource PrimaryHueMidForegroundBrush}"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
Value="True">
<Setter Property="Foreground"
Value="White" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ListBoxItem},Path=IsSelected}"
Value="True">
<Setter Property="Foreground"
Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
<ContentControl.Clip>
<EllipseGeometry RadiusX="16"
RadiusY="16"
Center="16,16" />
</ContentControl.Clip>
<ContentControl.Template>
<ControlTemplate TargetType="ContentControl">
<Border x:Name="ChipBackgroundBorder"
Background="{DynamicResource MaterialDesignChipBackground}">
<ContentPresenter Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
Value="True">
<Setter TargetName="ChipBackgroundBorder"
Property="Opacity"
Value="1" />
<Setter TargetName="ChipBackgroundBorder"
Property="Background"
Value="#1b5eb2" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ListBoxItem},Path=IsSelected}"
Value="True">
<Setter TargetName="ChipBackgroundBorder"
Property="Background"
Value="#1b5eb2" />
<Setter TargetName="ChipBackgroundBorder"
Property="Opacity"
Value="1" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
<ContentControl Content="{Binding Name}"
x:Name="TextBlock"
IsTabStop="False"
VerticalAlignment="Center"
Margin="8 0 12 0"
Grid.Column="1" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
此模板与您 use-case 的 Chip
模板几乎相同,但是,您可能需要考虑创建自己的模板并大幅简化它以仅满足您的要求。
我对 ListBoxItem
和 DataTrigger
有疑问。
当用鼠标单击芯片项目时,我想更改 Chip
项目的 Background
颜色。
我认为问题出在这行代码
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ListBoxItem},Path=IsSelected}"
Value="True">
<Setter Property="IconBackground"
Value="#1b5eb2" />
<Setter Property="Opacity"
Value="1"></Setter>
</DataTrigger>
运行 我的代码我得到了一个信号类别列表(如下面的屏幕截图所示):
但是,当我用鼠标点击它们时,圆圈的颜色没有改变。
它应该像这样工作(点击时):
我尝试了一些东西并检查了很多关于 DataTrigger
的主题,但我似乎无法弄清楚。
我的.xaml 观点
<ListBox Name="SignalCategories"
ItemsSource="{Binding DefinedSignalCategories}"
SelectionMode="Single"
HorizontalAlignment="Center"
VerticalAlignment="Top"
BorderThickness="0">
<!--changing default ListBoxItem to hide selection highlight-->
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<!--changing default orientation-->
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<!--custom view-->
<materialDesign:Chip Content="{Binding Name}"
Margin="5"
IconForeground="{DynamicResource PrimaryHueDarkForegroundBrush}">
<materialDesign:Chip.Style>
<Style TargetType="{x:Type materialDesign:Chip}">
<Setter Property="Opacity"
Value="0.85" />
<Setter Property="IconBackground"
Value="Gray"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Opacity"
Value="1" />
<Setter Property="IconBackground"
Value="#1b5eb2">
</Setter>
</Trigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ListBoxItem},Path=IsSelected}"
Value="True">
<Setter Property="IconBackground"
Value="#1b5eb2" />
<Setter Property="Opacity"
Value="1"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</materialDesign:Chip.Style>
<materialDesign:Chip.Icon>
<materialDesign:PackIcon Kind="{Binding IconName}" />
</materialDesign:Chip.Icon>
</materialDesign:Chip>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
我发现问题出在 materialDesign:Chip
上。
我在没有使用 materialDesign 的情况下重做了它,现在它可以正常工作了。
工作代码:
<ListBox.ItemTemplate>
<DataTemplate>
<!--custom view-->
<Grid Width="auto"
Height="30"
x:Name="grid1"
Margin="10">
<Border BorderBrush="Transparent"
HorizontalAlignment="Left"
Background="#939393"
Panel.ZIndex="1000"
BorderThickness="0"
CornerRadius="30"
Width="30"
Height="30"
x:Name="BorderCircle">
<materialDesign:PackIcon Kind="{Binding IconName}"
Margin="5"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Foreground="White" />
</Border>
<Border Background="#efefef"
BorderThickness="0"
CornerRadius="15"
HorizontalAlignment="Right"
Margin="10 0 0 0">
<TextBlock Text="{Binding Name}"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Margin="25 0 10 0" />
</Border>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}"
Value="True">
<Setter TargetName="BorderCircle"
Property="Background"
Value="#1b5eb2" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
输出:
这不起作用的原因是您误用了 Chip
控件。是一个类型derived from ButtonBase
, which means it is basically a button. It handles mouse click events, which sets the e.Handled
flag of the corresponding routed event arguments to true
. See The Concept of Handled供参考
The value of Handled affects how a routed event is reported or processed as it travels further along the route. If
Handled
istrue
in the event data for a routed event, then handlers that listen for that routed event on other elements are generally no longer invoked for that particular event instance.
因此,Chip
上的点击被 ListBoxItem
忽略,因此未被选中。您当然可以使用在 code-behind 中使用 handledEventsToo
注册点击处理程序的解决方法,如文章中所述,然后在可视化树中搜索 ListBoxItem
并设置 IsSelected
true
,但我不推荐它,因为首先使用它是错误的控件。由于 Chip
是一个按钮,因此它具有 Mouse Over 和 Pressed 的视觉状态以及您可以执行的其他状态和大量标记不需要也不必为了 使按钮表现得像不是按钮一样进行覆盖 。这没有意义。
你可以做的是 copy the essentials of the default style for Chip
并从中制作 DataTemplate
或自定义控件。以下数据模板应该适合您。
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.Resources>
<materialDesign:NullableToVisibilityConverter x:Key="NullableToVisibilityConverter" />
<materialDesign:PackIcon x:Key="Icon"
Kind="{Binding IconName}" />
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border CornerRadius="16"
Background="{DynamicResource MaterialDesignChipBackground}"
Grid.ColumnSpan="3" />
<ContentControl Grid.Column="0"
Content="{StaticResource Icon}"
Background="{DynamicResource PrimaryHueMidBrush}"
FontSize="17"
FontWeight="Regular"
IsTabStop="False"
Visibility="{Binding Source={StaticResource Icon}, Converter={StaticResource NullableToVisibilityConverter}}"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
Height="32"
Width="32">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Foreground" Value="{DynamicResource PrimaryHueMidForegroundBrush}"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
Value="True">
<Setter Property="Foreground"
Value="White" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ListBoxItem},Path=IsSelected}"
Value="True">
<Setter Property="Foreground"
Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
<ContentControl.Clip>
<EllipseGeometry RadiusX="16"
RadiusY="16"
Center="16,16" />
</ContentControl.Clip>
<ContentControl.Template>
<ControlTemplate TargetType="ContentControl">
<Border x:Name="ChipBackgroundBorder"
Background="{DynamicResource MaterialDesignChipBackground}">
<ContentPresenter Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
Value="True">
<Setter TargetName="ChipBackgroundBorder"
Property="Opacity"
Value="1" />
<Setter TargetName="ChipBackgroundBorder"
Property="Background"
Value="#1b5eb2" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ListBoxItem},Path=IsSelected}"
Value="True">
<Setter TargetName="ChipBackgroundBorder"
Property="Background"
Value="#1b5eb2" />
<Setter TargetName="ChipBackgroundBorder"
Property="Opacity"
Value="1" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
<ContentControl Content="{Binding Name}"
x:Name="TextBlock"
IsTabStop="False"
VerticalAlignment="Center"
Margin="8 0 12 0"
Grid.Column="1" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
此模板与您 use-case 的 Chip
模板几乎相同,但是,您可能需要考虑创建自己的模板并大幅简化它以仅满足您的要求。