WPF Custom Control: TemplateBinding to Image WPF Custom Control: TemplateBinding to Image wpf wpf

WPF Custom Control: TemplateBinding to Image


I am going to leave cwap's answer as the accepted answer, because it is technically correct. However, it turns out that there is an easier way to solve this problem.

TemplateBindings aren't first-class Binding objects. They are designed to be lightweight, so they are one-way, and they lack some features of other Binding objects. Most notably, they don't support known type converters associated with a target. See MacDonald, Pro WPF in C# 2008, p. 872. That's why cwap responds correctly that I would probably need to create a type converter and reference it specifically in the control template for my custom button.

But I don't have to use a TemplateBinding to bind the control template to the ImagePath property of my custom control. I can use a plain old Binding object. Here is the revised markup for my custom control's template:

<!-- Task Button Default Control Template--><Style TargetType="{x:Type local:TaskButton}">    <Setter Property="Template">        <Setter.Value>            <ControlTemplate TargetType="{x:Type local:TaskButton}">                <StackPanel Height="Auto" Orientation="Horizontal">                    <Image Source="{Binding Path=ImagePath, RelativeSource={RelativeSource TemplatedParent}}" Width="24" Height="24" Stretch="Fill" Margin="10,0,0,0" />                    <TextBlock Text="{TemplateBinding Text}"  HorizontalAlignment="Left" Foreground="{TemplateBinding Foreground}" FontWeight="Bold"  Margin="5,0,10,0" VerticalAlignment="Center" FontSize="12" />                </StackPanel>            </ControlTemplate>        </Setter.Value>    </Setter></Style>

If you look at the ImageControl in the template, you can see the change. Note the RelativeSource property in the same object. Setting this property to ={RelativeSource TemplatedParent} is what lets me enter a relative path in my Window1 instance of the TaskButton and have it resolved correctly in the custom control.

So my recommendation for others researching this thread would be to skip the value converter and simply switch from TemplateBinding to Binding for the Image property.

Thanks also to Marco Zhou, who provided this answer to a similar question in the MSDN WPF forum.


Image doesn't take a string as a source :) You can see this in intellisense. You need to bind on an ImageSource (Or use an IValueConverter to convert the string to an ImageSource)

See this question for some tips on how to do this conversion.


Actually neither of these answers are correct.

{TemplateBinding ImagePath} is nothing more than a shortcut for {Binding Path=ImagePath, RelativeSource={RelativeSource TemplatedParent}} and as such is almost completely identical.

Also if you provide a string for ImagePath it will correctly resolve to an ImageSource although you take a hit in application performance. The real issue has to do with relative and absolute image path on the supplied ImagePath="Resources\calendar.png" in the xaml for the test. This clues the compiler to think that the supplied path is absolute because of the use of \ instead of / in defining the path.

The reason that the long form of the binding works and the shortcut doesn't is that it provides clues to the compiler that the source of the image supplied (Resources\calendar.png) is a relative path not an absolute path, therefore the image is found and the binding works. If you debug the binding you will see that the shortcut tries resolve the supplied string into an image source but can not find the file "Resources\calendar.png" If you provide a full URI to the image i.e "C:\...\Resources\calendar.png" or the corresponding blend notation of "/application;component/Resources/calendar.png" then the image will be found and the binding resolved.

This point becomes really important when you are trying to reference images from an external source instead of those compiled as resources into the final compilation.