问题
Why does TemplateBinding
seems to fail in this specific case?
Take a basic extended button:
public class IconButton : Button
{
public ImageSource Icon
{
get { return (ImageSource)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public static readonly DependencyProperty ImageProperty =
DependencyProperty.Register("Icon", typeof(ImageSource), typeof(IconButton), new PropertyMetadata(null));
public IconButton()
{
DefaultStyleKey = typeof(IconButton);
}
}
The control template shows the icon using an OpacityMask
:
<Style TargetType="controls:IconButton">
<Setter Property="Width" Value="30" />
<Setter Property="Height" Value="30" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:IconButton">
<Grid>
<Rectangle Fill="{StaticResource PhoneForegroundBrush}"
Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
<Rectangle.OpacityMask>
<ImageBrush ImageSource="{TemplateBinding Icon}" />
</Rectangle.OpacityMask>
</Rectangle>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This fails silently -- the control appears as a solid rectangle. If I use a regular image, instead of the ImageBrush
, then the binding is successful:
<ControlTemplate TargetType="controls:IconButton">
<Grid>
<Image Source="{TemplateBinding Icon}" />
</Grid>
</ControlTemplate>
It also works correctly if I hard-code the image source path:
<ControlTemplate TargetType="controls:IconButton">
<Grid>
<Rectangle Fill="{StaticResource PhoneForegroundBrush}"
Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
<Rectangle.OpacityMask>
<ImageBrush ImageSource="/Images/appbar.next.rest.png" />
</Rectangle.OpacityMask>
</Rectangle>
</Grid>
</ControlTemplate>
So, why does TemplateBinding
fail inside an ImageBrush
?
Update
By deduction (and thanks to the answer from Chris), possible factors are:
- ImageBrush inherits from DependencyObject rather than from FrameworkElement
TemplateBinding
does not support implicit type conversion in the way that a normal binding does (ie, string-to-ImageSource)
I still don't see how the dots connect, though ...
回答1:
Interesting, I managed to replicate that behaviour from your example, and although I can't be entirely sure, I think I might understand what's going on.
Based on the answers to this question: WPF TemplateBinding vs RelativeSource TemplatedParent it seems that although two methods achieve the almost same thing, they differ in some key behaviours. The most relevant one being mentioned by Miroslav Nedyalkov -
"TemplateBindings don't allow value converting. They don't allow you to pass a Converter and don't automatically convert int to string for example (which is normal for a Binding)."
I would guess that in the second case, thebinding will use the built in WPF convertor to convert the bound string
/URI
to an ImageSource
(usual behaviour when specifying an ImageSource
- it's why you don't usually need to specify a binding convertor).
In the first case, you won't get the default value converting, so you won't see the mask. Interesting to see if it would work if a convertor was specified.
Edit: It looks there might be some additional complications from ImageBrush
not inheriting from FrameworkElement
: Bind an ImageBrush to a template with a DependencyProperty
回答2:
Here's a workaround. Bizarrely, using the RelativeSource TemplatedParent
binding instead of TemplateBinding
fixes the issue.
<ImageBrush ImageSource="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Icon}" />
Theoretically that is the exact same binding ... so, who knows? Whatever works.
来源:https://stackoverflow.com/questions/22134281/templatebinding-fails-when-the-target-is-an-imagebrush-imagesource