2
votes

Creating a button that uses an image for the background, when button pressed a different image is used for the background. Inherited from button and added two dependency properties of type ImageBrush, one is PressedBackground. There will later be an enum type property, which will be used to select which set of image resources will be loaded in 'PressedImage' and 'NormalImage'.

In controltemplate, using a data trigger for "IsPressed", to set the background property to the imagebrush in 'PressedBackground'. But when run, on press we have no background, debug tracing says "Cannot retrieve value using binding and no valid fallback value exists.

Problem is loading an imagebrush, from a dependency property into the background property, in the onpressed data trigger. I have tried all sorts to get a value into the background property, but with out success

Custom class snippet

public class QuantaImageButton : Button
{

    static QuantaImageButton()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(QuantaImageButton),
    new FrameworkPropertyMetadata(typeof(QuantaImageButton)));

    }


    public static readonly DependencyProperty PressedBackgroundProperty = DependencyProperty.Register(
        "PressedBackground", typeof(ImageBrush), typeof(QuantaImageButton), new PropertyMetadata(default(ImageBrush)));

    public ImageBrush PressedBackground
    {
        get { return (ImageBrush) GetValue(PressedBackgroundProperty); }
        set { SetValue(PressedBackgroundProperty, value); }
    }

    // other dependency properties
}

style is:

<Style x:Key="BtnQuanta" TargetType="controls:QuantaImageButton">
    <Setter Property="PressedBackground" Value="{StaticResource BtnMenuMediumDownImage}"/>
    <Setter Property="Background" Value="{StaticResource BtnMenuMediumUpImage}"/>
    <Setter Property= "Width" Value="500" />
    <Setter Property="Height" Value="470"/>
    <Setter Property="FontFamily" Value="Arial"/>
    <Setter Property="FontSize" Value="52"/>
    <Setter Property="Foreground" Value="White"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="Template" Value="{StaticResource QuantaBtnControlTemplate}"/>
</Style>


<ControlTemplate x:Key="QuantaBtnControlTemplate" TargetType="{x:Type    controls:QuantaImageButton}">
    <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
        <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
    </Border>
    <ControlTemplate.Triggers>
        <Trigger Property="IsPressed" Value="True">
            <Setter Property="Background" Value="{Binding PressedBackground, RelativeSource={RelativeSource TemplatedParent} }"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>
2
Why not use a StaticResource instead? Use the reference to static resource in your style and change it on the fly. Also look at the Output window it will give you information of where it actually is looking for the resource you pointed it to.XAMlMAX
We have about 40 different button styles, so this would involve 40 different styles, we want one style and one template, and we use an enumerated dependency property to set the 'button style', with the code behind setting the correct resource image in the two imagebrush properties - and I need to know how to access a dependency property value in a control template - correctlySytech
You could use BasedOn in that case, to make all of the styles aware of this. Don't know why you insist on creating functionality for a button that it already has. I think I am missing bigger picture here, but if you think about what are you doing with the button it is nothing that isn't already there.XAMlMAX
The resource is of type image brush, and works if the style sets the background property wit it - so I know the resource is ok.Sytech
VS debug shows this when button is pressedSytech

2 Answers

1
votes

I found the answer - as the debug text suggests - it cant find the property. The binding was incorrect - I have changed it to :

 <ControlTemplate.Triggers>
        <Trigger Property="IsPressed" Value="True">
            <Setter Property="Background" Value="{Binding PressedBackground, RelativeSource={RelativeSource Self} }"/>
        </Trigger>
    </ControlTemplate.Triggers>

The RelativeSource needs to be {RelativeSource Self} for the local object - not TemplateParent - which does not have the new property.

As an 'old' Winforms guy, moving over to WPF - it would be a great help if any one has a link to more explanation about this sort of binding and how you use it.

1
votes

if you add TargetName="border" to apply Background to the border inside Template, then {RelativeSource TemplatedParent} works:

<ControlTemplate.Triggers>
    <Trigger Property="IsPressed" Value="True">
        <Setter TargetName="border" Property="Background" 
                Value="{Binding Path=PressedBackground, RelativeSource={RelativeSource TemplatedParent} }"/>
    </Trigger>
</ControlTemplate.Triggers>

Adding TargetName changes target of binding, and apparently it affects RelativeSource resolution. However I cannot pin-point this subtle difference anywhere in the docs