WPF列表框选定的项目样式(突出显示是覆盖数据触发的样式)

时间:2012-12-30 04:40:24

标签: wpf user-controls listbox wpf-controls

我是一名移植到.Net的Access开发人员,我有一个WPF项目。由于我习惯于在Access中使用子表单,因此我创建了用户控件来执行此操作(可能本身就是一个问题,但不是我目前正在解决的问题)。

这个特定的用户控件(子窗体)有几个列表框绑定到后面的代码中的对象(VB - 我也没有进入那个辩论;我熟悉VBA)。这些列表框绑定到一个名为“IsAssigned”的布尔值。我创建了一个样式,根据该值将这些列表框中的项目更改为Greenish或Reddish。这很有效。

然后,我想更改该值以覆盖窗口的Highlight行为,并了解SystemColors.HighlightColor和ControlBrushKey。问题是我希望HighlightColor和ControlBrushKey颜色依赖于“IsAssigned”值。我显然无法嵌套触发器,除非我错过了某些东西。在下面的代码中,我将高亮值设置为绿色,仅用于说明我对此的理解。

所以我想要的是,当选择一个项目时,文本以粗体显示,带有黑色边框,并根据“IsAssigned”值保持绿色或红色的纯色。当同一个项目是突出显示的项目时,我真的希望前景是白色的,可能有更厚的边框。

要温柔 - 我不仅仅是一个菜鸟。

<UserControl.Resources>
    <Style TargetType="{x:Type ListBoxItem}" x:Key="ColorTrueAndFalse">
        <Style.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightColor}" Color="Green" />
            <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Green" />
        </Style.Resources>
        <Style.Triggers>
            <Trigger Property="IsSelected" Value="true">
                <Setter Property="FontWeight" Value="Bold" />
                <Setter Property="BorderBrush" Value="Black" />
            </Trigger>
            <DataTrigger Binding="{Binding IsAssigned}" Value="True">
                <Setter Property="Background">
                    <Setter.Value>
                        <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
                            <GradientStop Color="LightGreen" Offset="0" />
                            <GradientStop Color="Green" Offset="1" />
                            <GradientStop Color="LawnGreen" Offset="2" />
                        </LinearGradientBrush>
                    </Setter.Value>
                </Setter>
            </DataTrigger>
            <DataTrigger Binding="{Binding IsAssigned}" Value="False">
                <Setter Property="Background">
                    <Setter.Value>
                        <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
                            <GradientStop Color="LightCoral" Offset="0.5" />
                            <GradientStop Color="Coral" Offset="1" />
                            <GradientStop Color="Red" Offset="2" />
                        </LinearGradientBrush>
                    </Setter.Value>
                </Setter>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</UserControl.Resources>

2 个答案:

答案 0 :(得分:2)

DataContext的{​​{1}}与ListBoxItem本身的ListBox不同。 在{Binding IsAssigned}的样式中使用ListBoxItem时,您没有使用与DataContext相同的ListBox,因此无法找到该属性。

可以使用相对绑定轻松修复此问题 - 例如:

<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=DataContext.IsAssigned}" Value="true">

这会尝试绑定到ListBoxItems的父级。它上升到Visual Tree,直到找到ListBox并尝试使用前者的DataContext属性来查找IsAssigned。

因此,完整的解决方案将如下所示:

<Style.Triggers>
    <Trigger Property="IsSelected" Value="true">
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="BorderBrush" Value="Black" />
    </Trigger>
    <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=DataContext.IsAssigned}" Value="true">
        <Setter Property="Background">
          ....
        </Setter>
    </DataTrigger>

更新 - 突出显示:

首先注意Highlight画笔的名称是HighlightBrushKey,而不是你写的:

<Style.Resources>
    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Green" />

第二 - 使用此Trigger代替您使用的DataTrigger,更改所选项目的属性:

<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Self}}" Value="True">
    <Setter Property="FontWeight" Value="Bold" />
    <Setter Property="BorderBrush" Value="Black" />
</DataTrigger>

答案 1 :(得分:1)

在经历了很多我留下的小头发以及Blachshma正确方向的一些指示之后,我想出了一个解决方案。它主要基于标记found here

HighlightBrushKey和ControlBrushKey让我感到悲伤 - 我无法让他们识别数据触发器已经设置的底层颜色。我可以将它设置为静态颜色,但没有动态。也许投入更多的时间,这将是有效的。相反,我使用边框在数据触发器中设置颜色并更改任何所选项的字体和不透明度。边框颜色仍然保持不变,即使在一个列表框中选择一个项目并移动到另一个列表框中选择另一个项目,这正是我想要的。

这是我的XAML(为了简洁起见,省略了某些细节):

<UserControl.Resources>
    <Style TargetType="{x:Type ListBoxItem}" x:Key="BorderTrueAndFalse">
        <Style.Resources>
            <LinearGradientBrush x:Key="TrueBrush" EndPoint="1,0.5" StartPoint="0,0.5">
                ...
            </LinearGradientBrush>
            <LinearGradientBrush x:Key="FalseBrush" EndPoint="0,0.5" StartPoint="1,0.5">
                ...
            </LinearGradientBrush>
        </Style.Resources>
        <Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListBoxItem">
                    <Border  Name="Border" Padding="2" SnapsToDevicePixels="true">
                            <ContentPresenter />
                    </Border>
                    <ControlTemplate.Triggers>
                        <DataTrigger Binding="{Binding IsAssigned}" Value="True">
                            <Setter TargetName="Border" Property="Background" Value="{StaticResource TrueBrush}"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding IsAssigned}" Value="False">
                            <Setter TargetName="Border" Property="Background" Value="{StaticResource FalseBrush}"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Self}}" Value="True">
                            <Setter Property="FontWeight" Value="Bold" />
                            <Setter Property="Foreground" Value="White"/>
                            <Setter Property="Opacity" Value=".8"/>
                        </DataTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>

当然,我相信我对这里发生的事情有80%的肯定,但这个过程让我对绑定,触发器,样式,模板有了更深入的了解,以及为什么Access的开发速度更快!也许总有一天我会把文字设置为旋转,闪光,然后起床做一个小跳汰机,但是现在我是一个快乐的露营者。