views:

40

answers:

2

I have a button with a style that displays an image inside it. I would like to be able to specify the image it uses using the Content property on the button (or some other means).

How can accomplish this without actually nesting an image directly in the button.

<BitmapImage x:Key="closeImage" UriSource="close.png" />

I thought I could maybe specify the image file name like so:

<Button Content="{{StaticResource closeImage}" x:Name="closeButton" Click="closeButton_Click" Style="{DynamicResource WindowToolboxButton}"/>

Style:

    <Style x:Key="WindowToolboxButton" TargetType="{x:Type Button}">
        <Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
        <Setter Property="Background" Value="{StaticResource ButtonNormalBackgroundFill}"/>
        <Setter Property="BorderBrush" Value="{StaticResource ButtonBorder}"/>
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="HorizontalContentAlignment" Value="Center"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid x:Name="grid" Height="15" Width="15">
                        <Border x:Name="border" CornerRadius="2,2,2,2" BorderBrush="#FFBBCDD2" BorderThickness="1" Opacity="0" Margin="0">
                            <Border.Background>
                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                    <GradientStop Color="#FF82A3AC" Offset="1"/>
                                    <GradientStop Color="#7FCDD9DC"/>
                                </LinearGradientBrush>
                            </Border.Background>
                        </Border>
                        <Image x:Name="image" Source="close.png" Stretch="None" VerticalAlignment="Center" HorizontalAlignment="Center" >

                        </Image>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
A: 

I'm pretty sure I'm missing the problem of your question, but the following code works for me:

<Window.Resources>
 <Image x:Key="test" Source="/Images/ChangeCase.png"/>
</Window.Resources>

<!-- Using a Resource for the Content -->
<Button Width="100" Height="20" Content="{StaticResource test}"/>

<!-- Specifying the Content directly -->
<Button Width="100" Height="20">
 <Image Source="/Images/ChangeCase.png"/>
</Button>

Plus I spotted an error in your code:

<Button Content="{{StaticResource closeImage}" [...]

should be:

<Button Content="{StaticResource closeImage}" [...]

I don't quite understand what your style is doing. Why do you have the Content Property set to a StaticResource when you want to specify the image via style?

Edit:

Alright, I tried your style and it also works for me.

   <Style x:Key="WindowToolboxButton" TargetType="{x:Type Button}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid x:Name="grid" Height="15" Width="15">
                        <Border x:Name="border" CornerRadius="2,2,2,2" BorderBrush="#FFBBCDD2" BorderThickness="1" Opacity="0" Margin="0">
                            <Border.Background>
                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                    <GradientStop Color="#FF82A3AC" Offset="1"/>
                                    <GradientStop Color="#7FCDD9DC"/>
                                </LinearGradientBrush>
                            </Border.Background>
                        </Border>
                        <Image x:Name="image" Source="/Images/ChangeCase.png" Stretch="None" VerticalAlignment="Center" HorizontalAlignment="Center" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

  <Button Width="100" Height="20" Content="Test" Style="{DynamicResource WindowToolboxButton}"/>

The image is shown. However, I can't see your border due to the opacity-prop being set to 0.

The content that is given directly on the button is overriden by the style.

Maybe there is sth wrong with your image? Did you set its build-property to Resource?

Torsten
I guess my question really should have been: How do I define a button style where you can easily specify the image source used?
Chris
A: 

I think the correct way of doing this is

  1. Create a new custom control ImageButton which derives from Button
  2. Create a DP 'ImageSource' of type 'ImageSource' in ImageButton and in its style bind the Source of the Image to this DP.

Then you can use it like <ImageButton ImageSource={StaticResource ...}/>

If you try to add an image defined in a resource to a content control it will only work the first time. The second time you try to add the same image into another content control it will fail with "Specified visual is already a child of another visual..."

NVM
You can bypass that error by removing the content control and adding the new control to the control's parent. Your idea sounds better and cleanlier though, of course.
Torsten
I dont think that there is anyway of bypassing the error (I actually didn't correctly understand what you meant though). Any visual can only be a child on one visual. You simply cannot add the same visual(Image) as child of two different visuals. From what I understand Chris wants to possibly resue the images defined in the resource for different buttons. Adding this image directly as a child of a button will only work once. If the same image is added as a child of another button which is very much possible it will throw errors. The only way is to use ImageSource and not the image.
NVM
I rather think he wants to swap the images of the buttons. He's got a special button style (with a linear gradient background and so on), and the only thing that changes about the buttons is the image, which they display. Nevertheless I agree with you. One child can't have more than one parent. I stumbled across a similar problem, while adding a border around a child element programmatically, which forced me to remove the child element, before I could then add it with the border. However, I got mixed up, since it doesn't apply to this problem.
Torsten