Question

I have a CheckBox (placed above an image) whose Opacity is set to 0 by default. When IsMouseOver is true, the CheckBox Opacity property is animated from 0 to 1 and reversed when IsMouseOver is false. However, if the CheckBox IsSelected is true, then the reverse animation(i.e DataTrigger.ExitActions) should not execute. i.e CheckBox should remain visible if it is checked. In my XAML the checkbox is disappearing even when it is checked.

Following is my XAML:

<CheckBox VerticalAlignment="Center" HorizontalAlignment="Center">
        <CheckBox.Style>
            <Style TargetType="{x:Type CheckBox}">
                <Setter Property="Opacity" Value="0" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding ElementName=imageGrid, Path=IsMouseOver}" Value="True">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard Timeline.DesiredFrameRate="100">
                                    <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="00:00:00.400" />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                        <DataTrigger.ExitActions>
                            <BeginStoryboard>
                                <Storyboard Timeline.DesiredFrameRate="100">
                                    <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="00:00:00.400" />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.ExitActions>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource Mode=Self}}" Value="true">
                        <Setter Property="Opacity" Value="1" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </CheckBox.Style>
    </CheckBox>

Implemented the way @feO2x suggested. However it is not working as expected. Got it work in a simple application. However I intend to use the checkbox in a ListViewItem. Following is my XAML:

<Style x:Key="ThumbView_ItemContainerStyle" TargetType="{x:Type ListViewItem}">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Padding" Value="0"/>
    <Setter Property="Height" Value="175" />
    <Setter Property="Width" Value="125" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListViewItem}">
                <Grid Background="Pink" x:Name="mygrid">
                    <Rectangle Name="LBRect" Fill="Transparent" Opacity="0.195" />
                    <Image Name="posterImg" Margin="0,0,0,0" RenderOptions.BitmapScalingMode="HighQuality" SnapsToDevicePixels="True" HorizontalAlignment="Center" VerticalAlignment="Center" Source="{Binding Path=ProfilePic}" Height="125" MaxWidth="125" />
                    <CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}" VerticalAlignment="Center" HorizontalAlignment="Center" x:Name="CheckBox">
                        <CheckBox.RenderTransform>
                            <ScaleTransform ScaleX="1.1" ScaleY="1.1" />
                        </CheckBox.RenderTransform>

                        <CheckBox.Style>
                            <Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource ThumbViewCheckBoxStyle}">
                                <Setter Property="Opacity" Value="0" />
                                <Style.Triggers>
                                    <MultiDataTrigger>
                                        <MultiDataTrigger.Conditions>
                                            <Condition Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}" Value="False" />
                                            <Condition Binding="{Binding ElementName=CheckBox, Path=IsChecked}" Value="False" />
                                        </MultiDataTrigger.Conditions>
                                        <MultiDataTrigger.EnterActions>
                                            <BeginStoryboard>
                                                <Storyboard>
                                                    <DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.0" Duration="0:0:0.4" />
                                                </Storyboard>
                                            </BeginStoryboard>
                                        </MultiDataTrigger.EnterActions>
                                        <MultiDataTrigger.ExitActions>
                                            <BeginStoryboard>
                                                <Storyboard>
                                                    <DoubleAnimation Storyboard.TargetProperty="Opacity" To="1.0" Duration="0:0:0.4" />
                                                </Storyboard>
                                            </BeginStoryboard>
                                        </MultiDataTrigger.ExitActions>
                                    </MultiDataTrigger>
                                </Style.Triggers>
                            </Style>
                        </CheckBox.Style>
                    </CheckBox>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
Was it helpful?

Solution

This can be achieved with IMultiValueConverter in place. Pass two bindings to it i.e. IsMouseOver and IsChecked.

Converter:

public class MyConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, 
                          CultureInfo culture)
    {
        bool isMouseOver = (bool)values[0];
        bool isChecked = (bool)values[1];

        return isChecked || isMouseOver;
    }

    public object[] ConvertBack(object value, Type[] targetTypes,
                                object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

XAML:

<DataTrigger Value="True">
   <DataTrigger.Binding>
      <MultiBinding Converter="{StaticResource MyConverter}">
         <Binding Path="IsMouseOver" ElementName="imageGrid"/>
         <Binding Path="IsChecked" RelativeSource="{RelativeSource Self}"/>
      </MultiBinding>
   </DataTrigger.Binding>
   <!-- Rest same trigger -->
</DataTrigger>

Of course you need to add MyValueConverter instance as resource in your XAML file.

OTHER TIPS

Update February 26th: In your Style that is not working, you reference the checkbox the wrong way. ElementName can only be used in a binding if the target control was given a name and is accessible within the current WPF XAML namescope (you can learn about XAML namescopes here).

You should use a relative source within your binding to reference the CheckBox correctly: RelativeSource={RelativeSource Self}. The following ListView style shows the whole example:

<Style x:Key="ListViewItemStyle" TargetType="{x:Type ListViewItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate>
                <Border Background="{TemplateBinding Background}">
                    <Grid Margin="{TemplateBinding Padding}">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="150" />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="{Binding Name}" TextTrimming="CharacterEllipsis" />
                        <CheckBox IsChecked="{Binding IsSelected}" Grid.Column="1">
                            <CheckBox.Style>
                                <Style TargetType="{x:Type CheckBox}">
                                    <Setter Property="Opacity" Value="0.0" />
                                    <Style.Triggers>
                                        <MultiDataTrigger>
                                            <MultiDataTrigger.Conditions>
                                                <Condition Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
                                                        Value="False" />
                                                <Condition Binding="{Binding Path=IsChecked, RelativeSource={RelativeSource Self}}"
                                                        Value="False" />
                                            </MultiDataTrigger.Conditions>
                                            <MultiDataTrigger.EnterActions>
                                                <BeginStoryboard>
                                                    <Storyboard>
                                                        <DoubleAnimation Storyboard.TargetProperty="Opacity"
                                                                        To="0.0" Duration="0:0:0.4" />
                                                    </Storyboard>
                                                </BeginStoryboard>
                                            </MultiDataTrigger.EnterActions>
                                            <MultiDataTrigger.ExitActions>
                                                <BeginStoryboard>
                                                    <Storyboard>
                                                        <DoubleAnimation Storyboard.TargetProperty="Opacity"
                                                                        To="1.0" Duration="0:0:0.4" />
                                                    </Storyboard>
                                                </BeginStoryboard>
                                            </MultiDataTrigger.ExitActions>
                                        </MultiDataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </CheckBox.Style>
                        </CheckBox>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

You can download a working example from here (DropBox link).

Original Answer: You can use a MultiDataTrigger within your style to accomplish the behavior you want. Have a look at the following code:

<CheckBox Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Check Me" Name="CheckBox">
    <CheckBox.Style>
        <Style TargetType="{x:Type CheckBox}">
            <Setter Property="Opacity" Value="0.0" />
            <Style.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding ElementName=Rectangle, Path=IsMouseOver}" Value="False" />
                        <Condition Binding="{Binding ElementName=CheckBox, Path=IsChecked}" Value="False" />
                    </MultiDataTrigger.Conditions>
                    <MultiDataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetProperty="Opacity"
                                                 To="0.0"
                                                 Duration="0:0:0.4"
                                                 BeginTime="0:0:0.5" />
                            </Storyboard>
                        </BeginStoryboard>
                    </MultiDataTrigger.EnterActions>
                    <MultiDataTrigger.ExitActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetProperty="Opacity"
                                                 To="1.0"
                                                 Duration="0:0:0.4" />
                            </Storyboard>
                        </BeginStoryboard>
                    </MultiDataTrigger.ExitActions>
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>
    </CheckBox.Style>
</CheckBox>

A MultiDataTrigger is used to describe two conditions that have to be true for the enter actions to be executed. In this case I choose that the IsMouseOver property of a rectangle as well as the IsChecked property of the checkbox must both be false. Thus the checkbox is faded in when the mouse is over the rectangle and stays visible when it becomes checked.

You can download my full sample here (it's a Dropbox link).

Hope this helps you. If you have any questions, please feel free to leave a comment.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top