Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to customize a property inside a ContentControl in the "Pressed" VisualState?

I'm building Windows Phone app and I created a custom icon button that will be used over and over again. The button looks pretty much like the following picture:

Button mockup

To try to follow the DRY (Don't Repeat Yourself) principle I created a class that basically inherited from Button and added a custom parameter of type ControlTemplate called IconTemplate

I omitted the part about the property for the Text for brevity

public class IconButton : Button
{
    public static readonly DependencyProperty IconTemplateProperty =
                DependencyProperty.Register(
                    "IconTemplate",
                    typeof(ControlTemplate),
                    typeof(IconButton),
                    null);

    public ControlTemplate IconTemplate
    {
        get { return (ControlTemplate)GetValue(IconTemplateProperty); }
        set { SetValue(IconTemplateProperty, value); }
    }
}

After creating the class I made a Resource called Generic.xaml that applied some style to this class.

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:c="clr-namespace:PiadasEngracadas.Controls"

    <Style TargetType="c:IconButton">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderBrush" Value="{StaticResource PhoneForegroundBrush}"/>
        <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
        <Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/>
        <Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/>
        <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/>
        <Setter Property="Padding" Value="0"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="c:IconButton">
                    <Grid Background="{TemplateBinding Background}" x:Name="ButtonBackground">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="MouseOver"/>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="IconTemplateContainer">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneBackgroundBrush}"/>
                                         </ObjectAnimationUsingKeyFrames>
                                         <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
                                          </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="IconTemplateContainer">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <ContentControl x:Name="IconTemplateContainer"
                                        Template="{TemplateBinding IconTemplate}" />
                        <TextBlock VerticalAlignment="Bottom"
                                   HorizontalAlignment="Right"
                                   Margin="{StaticResource PhoneHorizontalMargin}"
                                   FontFamily="{StaticResource PhoneFontFamilyLight}"
                                   Text="{TemplateBinding Text}" />
                    </Grid>              
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

So I could simply create the button like this and the appearance would be correct.

<c:IconButton Text="Some Text"
              IconTemplate="{StaticResource IconsButtons.Sleepy}" />

The problem is that I want to change the Path's Stroke color when the user taps the button.

Since I'm going to use this button over and over again I thought that maybe it would be valuable to have another property that it would define the new stroke color when the button is tapped. Something like:

<c:IconButton Text="Some Text"
              TappedColor="#123456" // New property
              IconTemplate="{StaticResource IconsButtons.Sleepy}" />

But the problem is that I don't know how to change the color of the Path that is the Template (?) of the ContentControl. I was thinking about something like this:

<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Stroke" Storyboard.TargetName="(IconTemplateContainer).(Template).(Stroke)">

I know that this syntax is completely wrong but I wonder if someone can help me achieve my goal.

PS: I'm wrapping all the Paths in a ControlTemplate because using the Path directly and just binding it to the Content property of the ContentControl doesn't work on WP (or at least I'm not smart enough to make it work). Even in this case, how would I change a property of a object inside the ContentControls Contentfor a certainVisualState`?

UPDATE

The ControlTemplate code is as follows

<ControlTemplate x:Key="IconsButtons.Sleepy">
    <Path Data="M32.000099,44.658999C36.566562,44.658999 39.162999,47.058804 ...."
          Stretch="Uniform"
          Fill="#FFFFFFFF"
          Width="26"
          Height="26"
          Margin="0"
          RenderTransformOrigin="0.5,0.5">
        <Path.RenderTransform>
            <TransformGroup>
                <TransformGroup.Children>
                    <RotateTransform Angle="0" />
                    <ScaleTransform ScaleX="1" ScaleY="1" />
                </TransformGroup.Children>
            </TransformGroup>
        </Path.RenderTransform>
    </Path>
</ControlTemplate>
like image 685
Matheus Avatar asked Feb 02 '26 06:02

Matheus


1 Answers

You can do a TemplateBinding on the stroke color of the path to the foreground color of your IconButton. Then you can change the Foreground color of the IconButton and it will change the path color: Stroke="{TemplateBinding Foreground}"

like image 63
baueric Avatar answered Feb 04 '26 23:02

baueric



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!