tags:

views:

168

answers:

3

My user interface makes use of customized buttons: They contain both an image and a label.

I customized a single button manually, by setting its content to a grid holding an image and a label. However, since I need to have several such buttons, with different images and labels, I'd like to "extract" this pattern into something reusable. Basically, I just need a reusable object, with 2 properties (Image and Text) that I can set as the Content of several Buttons.

I looked at ContentTemplates, but I do not need to customize the appearance of the Button control itself, just its content.

What is the most appropriate technique to use for this?

+1  A: 

The easiest thing to do is create a UserControl for this:

  1. Create a UserControl
  2. Add a "ImageSource" dependency property to the UserControl class of type BitmapSource for the image
  3. Add a "Text" dependency property to the UserControl class of type string
  4. For your UserControl XAML, put the following XAML (simplified for brevity, you can change to suit your layout needs)

XAML for UserControl:

<UserControl DataContext="{Binding RelativeSource={RelativeSource Self}}" ...>
    <Button>
        <StackPanel Orientation="Horizontal">
           <Image Source="{Binding ImageSource}" />
           <TextBlock Text="{Binding Text}" />
        </StackPanel>
    </Button>
</UserControl>

Now you can reuse your user control wherever you want like so:

<myNS:MyUserControl ImageSource="MyImages/Foo.png" Text="Click here!" />
Drew Marsh
Thanks for the great suggestion. I am having some problems getting my XAML to build. The TemplateBinding elements result in the following error: "'ImageSource' member is not valid because it does not have a qualifying type name". I am pretty sure I created the DP properly, as I used the "propdb" snippet: public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register("ImageSource", typeof(BitmapSource), typeof(ImageButton), new UIPropertyMetadata());
Shteinitz
Ooops, sorry! Got my wires crossed with templates. You don't want to use TemplateBinding, you just want to use {Binding} with a RelativeSource of Self. Let me update the sample.
Drew Marsh
A: 

you could:

  1. Derive a class from button, add the two properties and overide the control template. using a usercontrol that contains the button you will be forced to do work arounds such as exposing the button as a property. (to attach commands, get the click event etc.)

  2. create your own straight class that has the two properties, and set it to be the buttons content, and create a data template for it, then the button stays as a straight button. If you want these properties to be set from the xaml, derive from control or something that allows dependency properties

I would use the second approach, its simple, and quick.

Aran Mulholland
A: 

I would say Control template editing as the easiest option to do this. Try using the below control template for all your buttons.I assumed the Button.Content is always the Label and Button.Tag always the Image Source

     <ControlTemplate x:Key="ImageText_button" TargetType="{x:Type Button}">
  <Grid Background="Transparent">
   <Image Source="{TemplateBinding Tag}" Stretch="Fill"/>
   <TextBlock Text="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
  </Grid>
 </ControlTemplate>

And all of your button XAML will be as below

<Button Content="MyLabel" Tag="\Image\abc.png" Template="{DynamicResource ImageText_button}" />
Jobi Joy
that is a hack, you lose your type safety (not that you have any in a binding anyway). And you cant actually set an image property, you have to bastardise theTag property, but i do kind of like it anyway :)
Aran Mulholland
Yeah I know it is a hack but 'Tag' property is really meant to use for this kind of small hacks. And as you said the obvious way is to create a subclass for button which is really hard for this simple problem.
Jobi Joy