tags:

views:

799

answers:

2

Hi, I'm very new to WPF, so please bear with me.

Basically I have defined a Style in a WPF UserControl to show buttons with an image as follows:

<UserControl.Resources>
    <Style TargetType="Button">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <TextBlock  HorizontalAlignment="Center" VerticalAlignment="Center">
                        <Image Width="16" Height="16" Stretch="UniformToFill"/>
                        <ContentPresenter/>
                    </TextBlock>
                </ControlTemplate>
            </Setter.Value>

        </Setter>
    </Style>
</UserControl.Resources>

I then add a load of buttons to a grid at runtime (it has to be at run time as the number and type of button is dynamic).

What I would like to do is set the image of the buttons at runtime as well. I have tried a number of ways, but none seem to work. Setting the source in the Xaml works fine. The code I'm trying is as follows:

Button b = new Button();
// Create source.
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(@"C:\SourceCode\DSA\DSALibrary\Icons\money.png");
bi.EndInit();

b.SetValue(Image.SourceProperty, bi);

Could anybody point me towards where I'm going wrong, if I were to guess, I would say that where I think I'm setting the value, I'm actually not.

Cheers

A: 

Can you confirm that it's a System.Windows.Controls.UserControl derived object you're creating?

My guess would be that the control loads it's bitmap when you create it so setting the image source property after that isn't being caught. Have you tried creating a button programmatically with a two-stage creation and setting it before you do the second stage?

You could try calling the button's Invalidate() function to make sure it redraws.

Jon Cage
+2  A: 

You can try to use the Content property of Button, and declare a DataTemplate for handling the content:

<UserControl.Resources>
    <Style TargetType="Button">
        <Setter Property="ContentTemplate">
            <Setter.Value>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image Width="16" Height="16" Stretch="UniformToFill" Source="{Binding}"/>
                        <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="My button text" />
                    </StackPanel>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <ContentPresenter/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</UserControl.Resources>

Set the BitmapImage on the content of your button, et voila :)

Arcturus
OK... I'm with you. I must admit I haven't hit binding yet. Could you point me in the direction of how I define what is "{Binding}"? Thanks
MrEdmundo
Just a quick point, I can't see how the text of the button is set in your example above?
MrEdmundo
When you set the Content on Button, the ContentControl (Button) will use a intern ContentPresenter. The ContentPresenter will set the Content as its DataSource. The DataSource property is the property which will determe the direct binding. So the {Binding} creates a binding to the DataSource, which happens to be the Content which is the Bitmap image... :)
Arcturus
Ahh I'm sorry.. I skimped the text.. let me add that ;)
Arcturus
OK, that looks good. But what if I want the text and the image to be dynamic?
MrEdmundo
You can also set a custom object as Content (b.Content = new { Image = bm, Text = "My awesome button" }; . See it as a holder object for an image and a piece of text.. Then the Bindings would change a bit.. for image: {Binding Path=Image} (your image property) and {Binding Path=Text} for your text property..
Arcturus
Got you, thanks a lot
MrEdmundo
No problem, glad I could help! :)
Arcturus
That all works great, although strangely, whereas my button used to just show as text (no button like look, which is what I want), they now look like buttons.
MrEdmundo
True, for the new look, you still want to override the Template property.. see my changed answer
Arcturus
Thank you, I just worked that out myself, literally 30 seconds before you post :)
MrEdmundo
haha ok :D....
Arcturus