3
votes

I have the following style and list box:

<Style x:Key="LwHListBoxItemStyle" TargetType="ListBoxItem">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="BorderBrush" Value="Transparent"/>
    <Setter Property="Padding" Value="0"/>
    <Setter Property="HorizontalContentAlignment" Value="Left"/>
    <Setter Property="VerticalContentAlignment" Value="Top"/>
    <Setter Property="Padding" Value="24, 0, 24, 0" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBoxItem">
                <Border x:Name="LayoutRoot" BorderBrush="#FFCCCCCC" BorderThickness="0, 0, 0, 1" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="MouseOver"/>
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="LayoutRoot">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource TransparentBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <DoubleAnimation Duration="0" To=".5" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="ContentContainer"/>
                                    <DoubleAnimation Duration="0" To="0.6" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="LayoutRoot" d:IsOptimized="True"/>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<ListBox x:Name="lbxContainer" Height="Auto" Width="Auto" ScrollViewer.VerticalScrollBarVisibility="Disabled" VerticalAlignment="Top" ItemContainerStyle="{StaticResource LwHListBoxItemStyle}" />

I used Expression Blend to create the style. I want the ListBoxItem to have a 60% opacity when disabled. I'm populating the ListBox programatically with ListBoxItems that have their IsEnabled property set based on certain criteria. I've stepped through the debugger and confirmed that the ListBoxItems do have IsEnabled = false, so my conclusion is that there must be something wrong with my xaml. Is there something I'm missing or doing wrong that is causing the items to not become opaque when disabled?

The ListBox is on a white background and has black text as the content. The opacity should make it gray. If I add opacity to the normal visual state, it shows up as intended for the normal state, but also for the Disabled state. I know the disabled items are actually disabled because I can't click on them. I figured that the code below would show normal state as opaque but disabled items without opacity.

<VisualState x:Name="Normal">
    <Storyboard>
        <DoubleAnimation Duration="0" To="0.6" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="LayoutRoot" d:IsOptimized="True"/>
    </Storyboard>
</VisualState>

Update: I'm pretty sure there is something wrong with my disabled state. Nothing I add in the disabled state takes hold, even if I change the background to blue. I am creating ListBoxItems programatically and setting the content property to a user control I have created. Could this be causing problems? It doesn't make sense to me because I can set the normal state with 60% opacity and it works, so why wouldn't the disabled state?

2

2 Answers

1
votes

You should not be using a ContentControl inside your control template. You should be using a ContentPresenter instead. You can run into weird issues by having a ContentControl displaying the content of another ContentControl.

Aside from that, the ListBoxItem will only go into the "Disabled" state, if the ListBoxItem.Content is not a Control. If the ListBoxItem.Content is a Control, then it will transition to the "Normal" state even if ListBoxItem.IsEnabled is false.

0
votes

You've created a style for the ListBoxItem, but not for the ListBox itself. And you don't have to, necessarily. The problem is that by default the ListBox has a white background.

So the first step is to set the ListBox background to Transparent like this...

<ListBox x:Name="lbxContainer" Background="Transparent" Height="Auto" Width="Auto" ScrollViewer.VerticalScrollBarVisibility="Disabled" VerticalAlignment="Top" ItemContainerStyle="{StaticResource LwHListBoxItemStyle}" />

Then I just made a couple changes to your ListBoxItem style...

<Style x:Key="LwHListBoxItemStyle" TargetType="ListBoxItem">
    <Setter Property="Background" Value="White"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="BorderBrush" Value="Transparent"/>
    <Setter Property="Padding" Value="0"/>
    <Setter Property="HorizontalContentAlignment" Value="Left"/>
    <Setter Property="VerticalContentAlignment" Value="Top"/>
    <Setter Property="Padding" Value="24, 0, 24, 0" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBoxItem">
                <Border x:Name="LayoutRoot" BorderBrush="#FFCCCCCC" Background="{TemplateBinding Background}" BorderThickness="0, 0, 0, 1" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="MouseOver"/>
                            <VisualState x:Name="Disabled">
                                <Storyboard>                                            
                                    <DoubleAnimation Duration="0" To="0.6" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="LayoutRoot" />
                                    <DoubleAnimation Duration="0" To="0.6" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="ContentContainer"/>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

And now as long as the container around the ListBox is not white, then a disabled ListBoxItem should appear translucent thanks to the Opacity setting.

For example...

<Grid Background="Black">
    <ListBox x:Name="lbxContainer" Background="Transparent" Height="Auto" Width="Auto" ScrollViewer.VerticalScrollBarVisibility="Disabled" VerticalAlignment="Top" ItemContainerStyle="{StaticResource LwHListBoxItemStyle}">
        <ListBoxItem Content="enabled a" />
        <ListBoxItem Content="disabled b" IsEnabled="False"/>
        <ListBoxItem Content="enabled c"/>
    </ListBox>
</Grid>

Will look like this...

disabled style