将资源绑定到自定义控件属性

时间:2011-02-07 17:48:21

标签: wpf wpf-controls binding

我正在制作一个自定义按钮,通常会显示略微褪色的文字,并在MouseOverMouseDown上显示完整力量的文字。我在我的控件的Generic.xaml中定义了两个资源来表示这些文本颜色的画笔:

<!-- Text Brushes -->
<SolidColorBrush x:Key="NormalTextBrush" Color="Black" />
<SolidColorBrush x:Key="FadedTextBrush" Color="Gray" />

控件在该配置中编译并正常工作。

但我想让控件用户使用自定义控件的Foreground属性设置文本颜色。所以,我将资源声明更改为:

<!-- 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'}" />

第二个声明使用HSL值转换器淡化文本颜色。

现在控件不起作用,我在输出窗口中收到以下错误:

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')

我不确定Data Error告诉我的是什么。任何人都可以告诉我发生了什么以及如何解决它?谢谢你的帮助。

2 个答案:

答案 0 :(得分:4)

RelativeSource TemplatedParent(IIRC)在控件模板中具有意义,它指的是应用模板的控件实例上的属性。

UserControl的内容不是UserControl的模板。因此,此绑定不会将父UserControl视为可行的目标。

错误消息指的是SolidColorBrush没有模板的事实;它不会扩展System.Windows.Controls.Control,这是(大多数)所有模板化UI控件的基本类型。有关模板的详细信息,请参阅Control.Template

您要做的是设置FindAncestor的相对来源。

{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}

这会走向可视(或是逻辑?)树,找到类型为UserControl的第一个祖先,然后绑定一个名为Foreground的公共属性。

然而如果将SolidColorBrush定义为Resource,则无效。资源不是视觉(或逻辑树,或两者兼有?仍然不清楚)的一部分,因此RelativeSource绑定将无法走树的祖先。

您必须直接在任何控件上使用绑定,以获得与UserControl相同的前景色。

答案 1 :(得分:2)

问题是您不能对资源中定义的元素使用RelativeSource绑定,因为它们不是可视树或逻辑树的一部分。

要解决此问题,您只需在设置对资源的引用的位置(在按钮的控件模板中)设置这些绑定。像这样:

<ControlTemplate TargetType="{x:Type Button}">
   <Border x:Name="brd" 
           TextBlock.Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource TemplatedParent}}">
      ...
   </Border>
   <ControlTemplate.Triggers>
      <Trigger Property="IsMouseOver"
               Value="True">
          <Setter TargetName="brd"
                  Property="TextBlock.Foreground"
                  Value="{Binding Path=Foreground, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource ColorConverter}, ConverterParameter='1.2'}"/>
      </Trigger>
   </ControlTemplate.Triggers>
</ControlTemplate>

换句话说,您无需定义资源 - NormalTextBrushFadedTextBrush