ControlTemplate LayoutTransform 绑定 System.Windows.Data 错误 2 或 4

ControlTemplate LayoutTransform Binding System.Windows.Data Error 2 or 4

我正在创建一个自定义 UserControl,它将作为一个容器,在其内容后面显示一个自定大小的水印。

ControlTemplate 的相关部分(我将在下面为您提供完整内容)是

    <TextBlock
                        Text="{TemplateBinding WatermarkText}"
                        Foreground="{TemplateBinding WatermarkBrush}"
                        HorizontalAlignment="Center"
                        VerticalAlignment="Center"
                        FontWeight="Bold">
                                <TextBlock.LayoutTransform>
                                    <RotateTransform Angle="{Binding WatermarkAngle,RelativeSource={RelativeSource AncestorType={x:Type local:WatermarkUserControl}}}"/>
                                </TextBlock.LayoutTransform>
                            </TextBlock>

我的 UserControl 具有 WatermarkText、WatermarkBrush、WatermarkAngle 和 WatermarkVisibility 的依赖属性(我将在下面包含)。请注意,WatermarkText、WatermarkBrush 和 WatermarkVisibility 的 TemplateBindings 都工作正常。

对 WatermarkAngle 使用 TemplateBinding 无效,因为 TemplateBinding 是轻量级 "binding",因此不支持 inheritance context。我最终得到的 WatermarkAngle 绑定(上图)确实有效;但报告绑定错误:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='[redacted namespace].WatermarkUserControl', AncestorLevel='1''. BindingExpression:Path=WatermarkAngle; DataItem=null; target element is 'RotateTransform' (HashCode=59772470); target property is 'Angle' (type 'Double')

那么有没有更好的方法,避免报错呢?鉴于绑定确实有效,为什么它会报告绑定错误? (如果我更改值,它会反映出来。)


问题到此结束。这里有你需要的所有部分,以满足MCVE:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

public class WatermarkUserControl : UserControl
{
    public static readonly DependencyProperty WatermarkTextProperty =
        DependencyProperty.Register(nameof(WatermarkText), typeof(string), typeof(WatermarkUserControl), new PropertyMetadata("Watermark"));
    public static readonly DependencyProperty WatermarkBrushProperty =
        DependencyProperty.Register(nameof(WatermarkBrush), typeof(Brush), typeof(WatermarkUserControl), new PropertyMetadata(new SolidColorBrush(Colors.LightGray)));
    public static readonly DependencyProperty WatermarkAngleProperty =
        DependencyProperty.Register(nameof(WatermarkAngle), typeof(double), typeof(WatermarkUserControl), new PropertyMetadata(0d));
    public static readonly DependencyProperty WatermarkVisibilityProperty =
        DependencyProperty.Register(nameof(WatermarkVisibility), typeof(Visibility), typeof(WatermarkUserControl), new PropertyMetadata(Visibility.Visible));

    public string WatermarkText
    {
        get { return (string)GetValue(WatermarkTextProperty); }
        set { SetValue(WatermarkTextProperty, value); }
    }

    public Brush WatermarkBrush
    {
        get { return (Brush)GetValue(WatermarkBrushProperty); }
        set { SetValue(WatermarkBrushProperty, value); }
    }

    public double WatermarkAngle
    {
        get { return (double)GetValue(WatermarkAngleProperty); }
        set { SetValue(WatermarkAngleProperty, value); }
    }

    public Visibility WatermarkVisibility
    {
        get { return (Visibility)GetValue(WatermarkVisibilityProperty); }
        set { SetValue(WatermarkVisibilityProperty, value); }
    }
}

资源字典:

<Style x:Key="WatermarkUserControlBaseStyle" TargetType="local:WatermarkUserControl">
    <Setter Property="Padding" Value="0"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:WatermarkUserControl">
                <Grid>
                    <local:NoSizeDecorator Visibility="{TemplateBinding WatermarkVisibility}">
                        <Viewbox>
                            <TextBlock
                                Text="{TemplateBinding WatermarkText}"
                                Foreground="{TemplateBinding WatermarkBrush}"
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                FontWeight="Bold">
                                <TextBlock.LayoutTransform>
                                    <RotateTransform Angle="{Binding WatermarkAngle,RelativeSource={RelativeSource AncestorType={x:Type local:WatermarkUserControl}}}"/>
                                </TextBlock.LayoutTransform>
                            </TextBlock>
                        </Viewbox>
                    </local:NoSizeDecorator>
                    <ContentPresenter Content="{TemplateBinding Content}"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style x:Key="DraftWatermarkStyle" TargetType="local:WatermarkUserControl" BasedOn="{StaticResource WatermarkUserControlBaseStyle}">
    <Setter Property="WatermarkText" Value="DRAFT"/>
    <Setter Property="WatermarkBrush" Value="LightPink"/>
    <Setter Property="WatermarkAngle" Value="-20"/>
</Style>

NoSizeDecorator 已定义 here

使用示例:

<local:WatermarkUserControl
    Style="{StaticResource DraftWatermarkStyle}"
    WatermarkVisibility="True">
    <StackPanel>
        <Label Content="Mr Smith"/>
        <Label Content="1 High Street"/>
        <Label Content="London"/>
    </StackPanel>
</local:WatermarkUserControl>

我已经想出办法了。它使错误消失了,它似乎仍然有效,而且我还没有发现任何副作用。

我在 ControlTemplate 中将 RotateTransform 声明为 Viewbox 内的本地资源,然后将其作为 StaticResource 绑定到 TextBlock 的 LayoutTransform 属性。所以问题中新版本的 Viewbox 看起来像这样:

<Viewbox>
    <Viewbox.Resources>
        <RotateTransform x:Key="RotateWatermarkTransform" Angle="{Binding WatermarkAngle,RelativeSource={RelativeSource TemplatedParent}}"/>
    </Viewbox.Resources>

    <TextBlock
        Text="{TemplateBinding WatermarkText}"
        Foreground="{TemplateBinding WatermarkBrush}"
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        FontWeight="Bold"
        LayoutTransform="{StaticResource RotateWatermarkTransform}"/>
</Viewbox>