I am creating a custom button that shows slightly faded text normally, and full-strength text on a MouseOver
or MouseDown
. I have defined two resources in the Generic.xaml
of my control to represent the brushes for these text colors:
<!-- Text Brushes -->
<SolidColorBrush x:Key="NormalTextBrush" Color="Black" />
<SolidColorBrush x:Key="FadedTextBrush" Color="Gray" />
The control compiles and works fine in that configuration.
But I want to let the control user set the text color, using the custom control's Foreground
property. So, I changed the resource declarations to this:
<!-- Text Brushes -->
<SolidColorBrush x:Key="NormalTextBrush" Color="{Binding Path=Foreground, RelativeSource={RelativeSource TemplatedParent}}" />
<SolidColorBrush x:Key="FadedTextBrush" Color="{Binding Path=Foreground, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource ColorConverter}, ConverterParameter='1.2'}" />
The second declaration uses an HSL
value converter to fade the text color.
Now the control doesn't work, and I get the following error in the output window:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Foreground; DataItem='TaskButton' (Name='Button1'); target element is 'SolidColorBrush' (HashCode=38118303); target property is 'Color' (type 'Color')
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Foreground; DataItem=null; target element is 'SolidColorBrush' (HashCode=47449297); target property is 'Color' (type 'Color')
I'm not sure what the Data Error
is telling me. Can anyone tell me what's going on and how to fix it? Thanks for your help.
The problem is that you cannot use
RelativeSource
bindings on elements defined in resources, because they are not a part of visual or logical tree.To fix this you just need to set these binding in places where you set the references to your resources (in the control template of your button). Something like this:
In other words, you don't need to define resourses -
NormalTextBrush
andFadedTextBrush
.RelativeSource TemplatedParent
only (IIRC) has meaning within a control template, and it refers to a property on the instance of the control on which the template is applied.A
UserControl
's content is not the template of theUserControl
. So this binding won't consider the parentUserControl
as a viable target.The error message refers to the fact that a
SolidColorBrush
does not have a template; it does not extendSystem.Windows.Controls.Control
, which is the base type of (most) all templated UI controls. SeeControl.Template
for more information about templating.What you want to do is set a relative source of
FindAncestor
.This will walk up the visual (or is it logical?) tree to find the first ancestor of type
UserControl
, then bind against a public property calledForeground
.However this will NOT work if the
SolidColorBrush
is defined as aResource
. Resources are not part of the visual (or logical tree, or both? still not clear) and therefore aRelativeSource
binding will not be able to walk the tree's ancestry.You will have to use the binding directly on whatever control you wish to have the same foreground color as the
UserControl
.