Currently, I'm working on a simple custom button that uses user supplied images as a background for the pressed and normal states. I've a lot of buttons so I decided to write a custom button and implement two properties for the pressed and normal states' pictures.
Here is the code I'm using
public partial class ThemeableButton : Button { public ThemeableButton() { InitializeComponent(); } public static readonly DependencyProperty PressedContentBackgroundSourceProperty = DependencyProperty.Register( "PressedContentBackgroundSource", typeof(ImageSource), typeof(ThemeableButton), null); public ImageSource PressedContentBackgroundSource { get { return (ImageSource)GetValue(PressedContentBackgroundSourceProperty); } set { (value as BitmapImage).CreateOptions = BitmapCreateOptions.BackgroundCreation; SetValue(PressedContentBackgroundSourceProperty, value); } } public static readonly DependencyProperty NormalContentBackgroundSourceProperty = DependencyProperty.Register("NormalContentBackgroundSource", typeof(ImageSource), typeof(ThemeableButton), null); public ImageSource NormalContentBackgroundSource { get { return (ImageSource)GetValue(NormalContentBackgroundSourceProperty); } set { (value as BitmapImage).CreateOptions = BitmapCreateOptions.BackgroundCreation; SetValue(NormalContentBackgroundSourceProperty, value); } } }
I wrote the style for this button as follows
<Style x:Key="ThemeableButtonTemplate" TargetType="MJbox_UIComponents_Controls:ThemeableButton"> <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="MJbox_UIComponents_Controls:ThemeableButton"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source" Storyboard.TargetName="ButtonBackground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{TemplateBinding NormalContentBackgroundSource}"> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source" Storyboard.TargetName="ButtonBackground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{TemplateBinding PressedContentBackgroundSource}"> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Border BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0"> <Image x:Name="ButtonBackground" Stretch="None" Source="{TemplateBinding NormalContentBackgroundSource}"/> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
I tried a simple example
<Controls:ThemeableButton Style="{StaticResource ThemeableButtonTemplate}" x:Name="btnDidntNeedIt" NormalContentBackgroundSource="{Binding Source={StaticResource DefaultTheme}, Path=DidntHaveButtonUnselected}" PressedContentBackgroundSource="{Binding Source={StaticResource DefaultTheme}, Path=DidntHaveButtonSelected}" />
but the image is not showing, I tried by removing the TemplateBinding from the style and replaced it with the relative source to the image file and it worked fine. I just don't wanna create a customized style for each button on the app. Any possible workaround?
I have encountered this before, TemplateBinding does not work for custom dependency properties on controls. See these related questions:
issues with template binding and binding of custom component
TemplateBinding does not work in certain cases(when using TranslateTransform)
I have always used this instead:
{Binding MyProperty, RelativeSource={RelativeSource TemplatedParent}}
It is semantically the same as TemplateBinding, and can also support value converters etc ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With