1

I have a Button control that I want to be able to reuse throughout project. Each time button enters a new state, a different image will be displayed. For now, I have Normal State and Pressed State.

Here's the XAML portion of the control:

<Button
    x:Class="customImageButton.ImageButton"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Button.Template>
      <ControlTemplate TargetType="{x:Type Button}">
         <Grid>
            <ContentControl Width="80">
                <Grid>
                    <Image Name="Normal" Source="{Binding NormalState}"/>
                    <Image Name="Pressed" Source="{Binding PressedState}" Visibility="Hidden"/>
                </Grid>
            </ContentControl>
         </Grid>
         <ControlTemplate.Triggers>
            <Trigger Property="IsPressed" Value="True">
               <Setter TargetName="Normal" Property="Visibility" Value="Hidden"/>
               <Setter TargetName="Pressed" Property="Visibility" Value="Visible"/>
            </Trigger>
         </ControlTemplate.Triggers>
      </ControlTemplate>
   </Button.Template>
</Button>

Here's the code-behind for the control:

namespace customImageButton
{
    public partial class ImageButton : Button
    {
        public ImageButton()
        {
            this.InitializeComponent();
        }

        public ImageSource NormalState
        {
            get { return base.GetValue(NormalStateProperty) as ImageSource; }
            set { base.SetValue(NormalStateProperty, value); }
        }

        public static readonly DependencyProperty NormalStateProperty =
            DependencyProperty.Register("NormalState", typeof(ImageSource), typeof(ImageButton));

        public ImageSource PressedState
        {
            get { return base.GetValue(PressedStateProperty) as ImageSource; }
            set { base.SetValue(PressedStateProperty, value); }
        }

        public static readonly DependencyProperty PressedStateProperty =
            DependencyProperty.Register("PressedState", typeof(ImageSource), typeof(ImageButton));
    }
}

...and here is its use:

<local:ImageButton Content="CustomButton" HorizontalAlignment="Left" 
                   VerticalAlignment="Top" NormalState="Resources/Normal.png"
                   PressedState="Resources/Pressed.png"/>

My problem is that the images I've provided are not displaying. The Build Action for both images is Resource and I have tried using absolute path; however, that provided the same result. What am I missing?

B.K.
  • 9,982
  • 10
  • 73
  • 105
  • Look at the answers here (make sure you also read the comments): [WPF image resources](http://stackoverflow.com/questions/347614/wpf-image-resources) –  Jul 28 '14 at 23:10
  • @elgonzo Implying that I haven't done that? That link does not assist me in any way. It's not a problem of managing the resources. – B.K. Jul 28 '14 at 23:21
  • The bindings should use `TemplateBinding`, as in `Source="{TemplateBinding NormalState}"`. – McGarnagle Jul 28 '14 at 23:21
  • @McGarnagle I get `The member "NormalState" is not recognized or is not accessible.` if I do that – B.K. Jul 28 '14 at 23:24
  • Oh, you also need `TargetType="{x:Type my:ImageButton}"` in the control template. – McGarnagle Jul 28 '14 at 23:26
  • @McGarnagle That wouldn't even be a valid code. – B.K. Jul 28 '14 at 23:28
  • Was using Silverlight syntax -- but the point is, your control template has to target your `ImageButton` type. – McGarnagle Jul 28 '14 at 23:29
  • Yeah, I don't know ... I posted that as an answer, because it works. Visual Studio does complain about it though. You should probably place your default style and its control template in `/Themes/Generic.xaml`, instead of inline like that. – McGarnagle Jul 28 '14 at 23:44

1 Answers1

1

Two problems with the code as listed:

  1. The bindings need to be TemplateBinding.
  2. The TargetType should refer to the "ImageButton" type, not Button.

Like this:

<ControlTemplate 
     xmlns:local="clr-namespace:customImageButton"
     TargetType="{x:Type local:ImageButton}">
     <Grid>
        <ContentControl Width="80">
            <Grid>
                <Image Name="Normal" Source="{TemplateBinding NormalState}"/>
                <Image Name="Pressed" Source="{TemplateBinding PressedState}" Visibility="Hidden"/>
            </Grid>
        </ContentControl>
     </Grid>

Note: The above builds and runs, but Visual Studio complains:

'ImageButton' ControlTemplate TargetType does not match templated type 'Button'.

I suggest putting the control template in its own Style in the Themes/Generic.xaml resource dictionary, rather than inline.

McGarnagle
  • 101,349
  • 31
  • 229
  • 260
  • 1
    You're the man! :) At first I thought you were crazy in the above comment exchange, but you're actually 100% right. Thanks for your patience and your time. I'll look into making the control template a resource, thanks. – B.K. Jul 28 '14 at 23:45
  • Just as an update: I followed your suggestion regarding moving the template into the `Generic.xaml` and the error went away. Thanks again. – B.K. Jul 29 '14 at 00:26