Template Binding in Control template
Asked Answered
P

4

22

I have the following control template.

I wish to set the source property for the image control in the control template using Template Binding.

But since this is a control template for button control and the button control doesn't have source property, i can't use TemplateBinding in this case.

<ControlTemplate x:Key="BtnTemplate" TargetType="Button">
        <Border CornerRadius="5"  Margin="15" Cursor="Hand">
            <StackPanel>
                <Image Name="Img" Style="{StaticResource ImageStyle}" Source="temp.jpg" Height="100" Width="100" Margin="5"></Image>
                <Label Content="{TemplateBinding Content}" Background="Transparent" Margin="2"></Label>
            </StackPanel>
        </Border>
    </ControlTemplate>

Since i have to set different images for different instances of button, i can't hardcode the path as well.

Please let me know how to tackle this situation.

Priapism answered 9/1, 2011 at 10:47 Comment(0)
C
36

I'd suggest using dynamic resources, e.g. define the template as follows:

<ControlTemplate x:Key="buttonTemplate" TargetType="Button">
    <Border CornerRadius="5"  Margin="15" Cursor="Hand">
        <StackPanel Orientation="Horizontal" Background="Yellow">
            <Image Source="{DynamicResource ResourceKey=Img}" Height="100" Width="100" Margin="5"></Image>
            <Label Content="{TemplateBinding Content}" Background="Transparent" Margin="2"></Label>
        </StackPanel>
    </Border>
</ControlTemplate>

And use it like this:

<Button Content="Button" Template="{StaticResource ResourceKey=buttonTemplate}">
    <Button.Resources>
        <ImageSource x:Key="Img">SomeUri.png/</ImageSource>
    </Button.Resources>
</Button>
Ceramics answered 9/1, 2011 at 11:9 Comment(1)
Is it possible to use the Button in a much more concise manner? Like <CustomButton Content="Button" Icon="SomeUri.png" /> ? I am struck with this, could you please help me? https://mcmap.net/q/587816/-datatrigger-does-not-fire-on-a-derived-class-of-a-button/640607Tonguelashing
W
5

TemplateBinding is a lightweight "binding", it doesn't support some features of traditional Binding, such as automatically type conversion using the known type converters associated with the target property (such as converting the string URI into a BitmapSource instance).

The following code can work properly:

<Window x:Class="GridScroll.Window2"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window2">
<Window.Resources>
    <Style TargetType="{x:Type Button}" x:Key="ButtonStyle">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border CornerRadius="5"  Margin="15" Cursor="Hand" Background="Red">
                        <StackPanel Orientation="Horizontal" Background="White">
                            <Image Name="Img" Source="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}}" Margin="5"></Image>
                            <Label Content="{TemplateBinding Content}" Margin="2"></Label>
                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>


</Window.Resources>
<StackPanel Orientation="Horizontal">
    <Button Style="{StaticResource ButtonStyle}" Tag="a.jpeg" Content="a"/>
    <Button Style="{StaticResource ButtonStyle}" Tag="b.png" Content="b"/>
</StackPanel>

Wineglass answered 9/1, 2011 at 11:5 Comment(3)
is there any other way to do it rather than having Tag.? I am worried coz, later i might have multiple controls in my control template and i would like to set the properties at the time of creating object. But since Tag is already used, i will not be able use that again.Priapism
You can do as Kent suggests.Derive from button and create your own control.Add your custom dependency property and use as i use tagWineglass
My problem was slightly different than the original post, but this was the only solution that did the trick. I spent all morning on this, because errors in a single resource dictionary were preventing the UI from loading in several xaml designers throughout our application. Seriously, thank you.Scheider
B
3

You haven't really said how you expect consumers of your button to set the source. You could use the Button.Tag property, for example, and then bind to that in your template. Or you could define your own control:

public class ImageButton : Button
{
    // add Source dependency property a la Image
}

And then the template:

<ControlTemplate TargetType="ImageButton">
    <Border CornerRadius="5"  Margin="15" Cursor="Hand">
        <StackPanel>
            <Image Name="Img" Style="{StaticResource ImageStyle}" Source="{TempateBinding Source}" Height="100" Width="100" Margin="5"></Image>
            <Label Content="{TemplateBinding Content}" Background="Transparent" Margin="2"></Label>
        </StackPanel>
    </Border>
</ControlTemplate>
Beller answered 9/1, 2011 at 10:52 Comment(2)
i used tag property but that doesn't work. Source="{TemplateBinding Tag}" and while creating the button, Tag="Temp.jpg" but this doesn't work. i wish to set the source only in XAML no codebehind. Also, Tag might not be a good idea as there can be many controls within the controltemplate for whom i would want to set a few properties at the time of creation of the object.Priapism
That doesn't work because Source is of type ImageSource, and "Temp.jpg" is a string. You'll need to use a converter to convert strings to ImageSources, much like the Image control does.Beller
F
1

I'm not sure that I understood your problem very well but why don't you use ContentPresenter? It allows to move the code for your Image at the higher level.

<ControlTemplate x:Key="BtnTemplate" TargetType="Button">
  ...
  <ContentPresenter/>
</ControlTemplate>
...
<Button Template="{StaticResource BtnTemplate}">
  <Image .../>
</Button>
Ferrochromium answered 9/1, 2011 at 11:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.