Search code examples
wpfdatatemplatecontroltemplatevisualstatemanager

One out of two buttons using same ControlTemplate does not animate


I have a ListView that uses a DataTemplate to render out each item, with each item having an Edit and Remove button. The two buttons are templated so that they use a Path to display an icon, and animate with a storyboard when the mouse over happens.

The animation changes the Opacity and a trigger is used to add a dropshadow effect on MouseOver. The problem that I have is that despite the two buttons sharing the same templates, only one of them has the desired behavior of animating when moused over regardless if the ListViewItem is selected not. The 2nd one (the Edit button) will not animate unless I first select it's ListViewItem.

Images to demonstrate

Untouched ListView: The trash can (remove) works properly, while the edit is fully highlighted. Moving the mouse over the edit button results in none of the animations playing.

In this state, the ListViewItem does not have a mouse over it, so there are no MouseOver effects (change of color etc) shown.

Initial state

Mouse over on the Remove button: The remove button continues to work as expected. Highlighting on mouse over with my effect.

In this state (and all following states), the ListViewItem has the MouseOver it, causing the styling to reflect it.

Remove button working

Selecting ListViewItem lets Edit animation start working: When I select the ListViewItem, the Edit button now goes ahead and starts to animate right.

Remove button working

Animations Working w/ Selected ListViewItem: Now you can see the Edit button lighting up when moused over.

enter image description here

I'm not sure why two buttons, sharing the same template would act differently.

The ListView

This is the ListView, using the AdminQuantlistAttributeTemplate, rendering out the content you see in the above pictures.

<ListView DockPanel.Dock="Top"
            Margin="5 0 0 0"
            x:Name="AttributesListView"
            ItemsSource="{Binding Path=AttributesView}" 
            ItemTemplate="{StaticResource AdminQuantlistAttributeTemplate}"
            SelectedItem="{Binding Path=SelectedAttribute}"/>

The ItemTemplate

This item template is what contains the two buttons in question. I have also tried to re-organize them, so that the remove button is first. It does not matter in what order I put the buttons in my XAML, the edit button continues to be broken until the ListViewItem is selected.

<DataTemplate x:Key="AdminQuantlistAttributeTemplate"
              DataType="qlModels:QuantlistAttribute">
    <GroupBox>
        <GroupBox.Header>
            <TextBlock FontSize="14"
                       Foreground="{DynamicResource IdealForegroundColorBrush}">
                <Run Text="Attribute" />
                <Run Text="{Binding Path=SortOrder, Converter={StaticResource IncrementNumberConverter}, ConverterParameter=1}" />
            </TextBlock>
        </GroupBox.Header>

        <DockPanel LastChildFill="True">
            <StackPanel DockPanel.Dock="Left"
                        Margin="0 0 15 0">

<!-- The broken Edit Button -->
                <Button Command="{Binding ElementName=AttributesListView,
                        Path=DataContext.EditAttributeCommand}"
                        Margin="0 0 0 20"
                        Template="{DynamicResource ButtonIconTemplate}"
                        ToolTip="Edit Quantlist Attribute">
                    <Rectangle Width="20"
                               Height="20"
                               Fill="{Binding Path=Foreground,
                               RelativeSource={RelativeSource AncestorType=Button,
                               Mode=FindAncestor}}"
                               OpacityMask="{StaticResource EditIconBrush}" />
                </Button>

<!-- The working Remove Button -->
                <Button Command="{Binding ElementName=AttributesListView,
                        Path=DataContext.RemoveAttributeCommand}"
                        Template="{DynamicResource ButtonIconTemplate}"
                        ToolTip="Delete Quantlist Attribute">
                    <Rectangle Width="20"
                               Height="20"
                               Fill="{Binding Path=Foreground,
                               RelativeSource={RelativeSource AncestorType=Button,
                               Mode=FindAncestor}}"
                               OpacityMask="{StaticResource DeleteIconBrush}" />
                </Button>
            </StackPanel>

            <TextBlock DockPanel.Dock="Top">
                <Run Text="Weight"
                     FontWeight="Bold" />
                <Run Text="{Binding Path=AttributeWeight.Name}" />
            </TextBlock>
            <TextBlock Text="{Binding Path=Narrative}"
                       DockPanel.Dock="Top" />
            <ItemsControl ItemsSource="{Binding Path=References}"
                          DockPanel.Dock="Top">

                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>

                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Margin="0 0 20 0">
                            <Run Text="Reference:"
                                 FontWeight="Bold"
                                 FontSize="13" />
                            <Run Text="{Binding Path=Reference}" />
                        </TextBlock>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>

            </ItemsControl>
        </DockPanel>
    </GroupBox>
</DataTemplate>

The ButtonIconTemplate

This is the template that the buttons are actually using. Note that I am using this template in multiple locations through-out the app and it works fine. It is used in GroupBox and Expander headers, DataGrid columns with multiple buttons and as stand-alone controls. Just when used within this ListView (only place in the app I am using it like this), does it not work.

<ControlTemplate x:Key="ButtonIconTemplate"
                 TargetType="Button">
    <Grid>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CommonStates">
                <VisualState x:Name="MouseOver">
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetProperty="Opacity"
                                    To="1"
                                    Duration="0:0:0.05" />
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Normal">
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetProperty="Opacity"
                                    To="0.5"
                                    Duration="0:0:0.05" />
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <Rectangle x:Name="ButtonRect"
                   Fill="Transparent" />
        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                          Content="{TemplateBinding Content}"
                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
        </ContentPresenter>
    </Grid>

    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver"
                 Value="True">
            <Setter Property="Effect">
                <Setter.Value>
                    <DropShadowEffect ShadowDepth="-5"
                                      Color="{DynamicResource BlackColor}"
                                      Opacity="1"
                                      BlurRadius="15" />
                </Setter.Value>
            </Setter>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

Visual Brushes used by Buttons

<VisualBrush x:Key="DeleteIconBrush"
             Stretch="Uniform">
    <VisualBrush.Visual>
        <Canvas Width="24"
                Height="24">
            <Path Fill="#FF000000"
                  Data="F1 M 25.3333,23.75L 50.6667,23.75C 51.5411,23.75 51.8541,27.3125 51.8541,27.3125L 24.1458,27.3125C 24.1458,27.3125 24.4589,23.75 25.3333,23.75 Z M 35.625,19.7917L 40.375,19.7917C 40.8122,19.7917 41.9583,20.9378 41.9583,21.375C 41.9583,21.8122 40.8122,22.9584 40.375,22.9584L 35.625,22.9584C 35.1878,22.9584 34.0416,21.8122 34.0416,21.375C 34.0416,20.9378 35.1878,19.7917 35.625,19.7917 Z M 27.7083,28.5L 48.2916,28.5C 49.1661,28.5 49.875,29.2089 49.875,30.0834L 48.2916,53.8334C 48.2916,54.7078 47.5828,55.4167 46.7083,55.4167L 29.2917,55.4167C 28.4172,55.4167 27.7083,54.7078 27.7083,53.8334L 26.125,30.0834C 26.125,29.2089 26.8339,28.5 27.7083,28.5 Z M 30.0833,31.6667L 30.4792,52.25L 33.25,52.25L 32.8542,31.6667L 30.0833,31.6667 Z M 36.4167,31.6667L 36.4167,52.25L 39.5833,52.25L 39.5833,31.6667L 36.4167,31.6667 Z M 43.1458,31.6667L 42.75,52.25L 45.5208,52.25L 45.9167,31.6667L 43.1458,31.6667 Z " />
        </Canvas>
    </VisualBrush.Visual>
</VisualBrush>

<VisualBrush x:Key="EditIconBrush" 
             Stretch="Uniform">
    <VisualBrush.Visual>
        <Canvas Width="24" 
                Height="24">
            <Path Fill="{DynamicResource BlackBrush}" 
                  Data="M20.71,4.04C21.1,3.65 21.1,3 20.71,2.63L18.37,0.29C18,-0.1 17.35,-0.1 16.96,0.29L15,2.25L18.75,6M17.75,7L14,3.25L4,13.25V17H7.75L17.75,7Z" />
        </Canvas>
    </VisualBrush.Visual>
</VisualBrush>

Any help in troubleshooting this would be awesome.

Edit

It turns out that the Edit button had its CanExecute method returning false (which was expected). When I have CanExecute return true always, the animation works right.

So now the question is, how do I let the storyboard stuff all work, when the button is disabled?


Solution

  • I guess the problem is that EditAttributeCommand.CanExecute returns false and it prevents from being animated. This is the only thing which differs those two buttons, that's why this is my guess.