C# 如何绑定到Style.Resource中的附加属性?

C# 如何绑定到Style.Resource中的附加属性?,c#,.net,wpf,xaml,C#,.net,Wpf,Xaml,我正在尝试使用附加属性在文本框的背景中创建提示文本标签,但无法解析与样式资源中文本标题的绑定: 样式定义: <Style x:Key="CueBannerTextBoxStyle" TargetType="TextBox"> <Style.Resources> <VisualBrush x:Key="CueBannerBrush" AlignmentX="Left" Ali

我正在尝试使用附加属性在文本框的背景中创建提示文本标签,但无法解析与样式资源中文本标题的绑定:

样式定义:

<Style x:Key="CueBannerTextBoxStyle"
       TargetType="TextBox">
  <Style.Resources>
    <VisualBrush x:Key="CueBannerBrush"
                 AlignmentX="Left"
                 AlignmentY="Center"
                 Stretch="None">
      <VisualBrush.Visual>
        <Label Content="{Binding Path=(EnhancedControls:CueBannerTextBox.Caption), RelativeSource={RelativeSource AncestorType={x:Type TextBox}}}"
               Foreground="LightGray"
               Background="White"
               Width="200" />
      </VisualBrush.Visual>
    </VisualBrush>
  </Style.Resources>
  <Style.Triggers>
    <Trigger Property="Text"
             Value="{x:Static sys:String.Empty}">
      <Setter Property="Background"
              Value="{DynamicResource CueBannerBrush}" />
    </Trigger>
    <Trigger Property="Text"
             Value="{x:Null}">
      <Setter Property="Background"
              Value="{DynamicResource CueBannerBrush}" />
    </Trigger>
    <Trigger Property="IsKeyboardFocused"
             Value="True">
      <Setter Property="Background"
              Value="White" />
    </Trigger>
  </Style.Triggers>
</Style>
用法:

<TextBox x:Name="txtProductInterfaceStorageId" 
                 EnhancedControls:CueBannerTextBox.Caption="myCustomCaption"
                 Width="200" 
                 Margin="5" 
                 Style="{StaticResource CueBannerTextBoxStyle}" />

其思想是,您可以在创建文本框时定义视觉画笔中使用的文本提示,但我得到一个绑定错误:

System.Windows.Data错误:4:找不到用于绑定的源,引用为“RelativeSource FindAncestor,AncestorType='System.Windows.Controls.TextBox',AncestorLevel='1'。BindingExpression:路径=(0);DataItem=null;目标元素为“标签”(名称=“”);目标属性为“内容”(类型为“对象”)

如果我只是在样式中硬编码Label.Content属性,代码就可以正常工作

有什么想法吗?

这里的问题与
样式
的工作方式有关:基本上,将创建一个
样式
的“副本”(在第一次引用时),在这一点上,可能有多个
文本框
控件要将此
样式
应用到-它将用于哪个相对资源

(可能的)答案是使用
模板
而不是
样式
——通过控件或数据模板,您将能够访问
模板属性的可视化树
,这将帮助您找到需要的位置

编辑:进一步考虑,我可能不正确……当我回到电脑前时,我会准备一个快速测试工具,看看我是否能证明/反驳这一点

进一步编辑:虽然我最初说的可以说是“真实的”,但这不是你的问题;劳尔所说的:视觉树是正确的:

  • 您正在将
    TextBox
    上的
    Background
    属性设置为
    VisualBrush
    实例
  • 该画笔的
    视觉
    未映射到控件的视觉树中
  • 因此,任何
    {RelativeSource FindAncestor}
    导航将失败,因为该视觉的父项将为空
  • 无论是声明为
    样式
    还是
    控制模板
    ,情况都是如此
  • 尽管如此,依赖
    ElementName
    显然是不理想的,因为它降低了定义的可重用性
那么,该怎么办

我一夜之间绞尽脑汁,试图想出一种方法,将正确的继承上下文整理到包含的笔刷中,但收效甚微……我确实想出了一种超级黑客的方法,然而:

首先是helper属性(注意:我通常不会这样设计代码,但会尽量节省空间):

现在更新的XAML:

<Style x:Key="CueBannerTextBoxStyle"
       TargetType="{x:Type TextBox}">
  <Style.Triggers>
    <Trigger Property="TextBox.Text"
             Value="{x:Static sys:String.Empty}">
      <Setter Property="local:HackyMess.Background">
        <Setter.Value>
          <VisualBrush AlignmentX="Left"
                       AlignmentY="Center"
                       Stretch="None">
            <VisualBrush.Visual>
              <Label Content="{Binding Path=(local:HackyMess.Caption)}"
                     Foreground="LightGray"
                     Background="White"
                     Width="200" />
            </VisualBrush.Visual>
          </VisualBrush>
        </Setter.Value>
      </Setter>
    </Trigger>
    <Trigger Property="IsKeyboardFocused"
             Value="True">
      <Setter Property="local:HackyMess.Background"
              Value="White" />
    </Trigger>
  </Style.Triggers>
</Style>
<TextBox x:Name="txtProductInterfaceStorageId"
         local:HackyMess.Caption="myCustomCaption"
         local:HackyMess.Context="{Binding RelativeSource={RelativeSource Self}}"
         Width="200"
         Margin="5"
         Style="{StaticResource CueBannerTextBoxStyle}" />
<TextBox x:Name="txtProductInterfaceStorageId2"
         local:HackyMess.Caption="myCustomCaption2"
         local:HackyMess.Context="{Binding RelativeSource={RelativeSource Self}}"
         Width="200"
         Margin="5"
         Style="{StaticResource CueBannerTextBoxStyle}" />

问题在于
可视化笔刷中的
标签
不是
文本框
的可视子项,这就是绑定不起作用的原因。我的解决方案是使用
ElementName
绑定。但是您正在创建的可视笔刷位于
样式
的字典资源中,然后
元素名称
绑定将无法工作,因为找不到元素id。解决方法是在全局字典资源中创建
可视笔刷
。查看此XAML代码了解
VisualBrush

<Window.Resources>
  <VisualBrush x:Key="CueBannerBrush"
               AlignmentX="Left"
               AlignmentY="Center"
               Stretch="None">
    <VisualBrush.Visual>
      <Label Content="{Binding Path=(EnhancedControls:CueBannerTextBox.Caption), ElementName=txtProductInterfaceStorageId}"
             Foreground="#4F48DD"
             Background="#B72121"
             Width="200"
             Height="200" />
    </VisualBrush.Visual>
  </VisualBrush>
  <Style x:Key="CueBannerTextBoxStyle"
         TargetType="{x:Type TextBox}">
    <Style.Triggers>
      <Trigger Property="Text"
               Value="{x:Static System:String.Empty}">
        <Setter Property="Background"
                Value="{DynamicResource CueBannerBrush}" />
      </Trigger>
      <Trigger Property="Text"
               Value="{x:Null}">
        <Setter Property="Background"
                Value="{DynamicResource CueBannerBrush}" />
      </Trigger>
      <Trigger Property="IsKeyboardFocused"
               Value="True">
        <Setter Property="Background"
                Value="White" />
      </Trigger>
    </Style.Triggers>
  </Style>
</Window.Resources>

这段代码应该有效。没有更多的代码需要更改,所以我不会重写所有的代码


希望这个解决方案对你有用

看起来它只是将元素名硬编码到样式中-如何重用?我只能有一个文本框使用此解决方案?好的,我会尝试-让我知道如果你成功!谢谢
<Style x:Key="CueBannerTextBoxStyle"
       TargetType="{x:Type TextBox}">
  <Style.Triggers>
    <Trigger Property="TextBox.Text"
             Value="{x:Static sys:String.Empty}">
      <Setter Property="local:HackyMess.Background">
        <Setter.Value>
          <VisualBrush AlignmentX="Left"
                       AlignmentY="Center"
                       Stretch="None">
            <VisualBrush.Visual>
              <Label Content="{Binding Path=(local:HackyMess.Caption)}"
                     Foreground="LightGray"
                     Background="White"
                     Width="200" />
            </VisualBrush.Visual>
          </VisualBrush>
        </Setter.Value>
      </Setter>
    </Trigger>
    <Trigger Property="IsKeyboardFocused"
             Value="True">
      <Setter Property="local:HackyMess.Background"
              Value="White" />
    </Trigger>
  </Style.Triggers>
</Style>
<TextBox x:Name="txtProductInterfaceStorageId"
         local:HackyMess.Caption="myCustomCaption"
         local:HackyMess.Context="{Binding RelativeSource={RelativeSource Self}}"
         Width="200"
         Margin="5"
         Style="{StaticResource CueBannerTextBoxStyle}" />
<TextBox x:Name="txtProductInterfaceStorageId2"
         local:HackyMess.Caption="myCustomCaption2"
         local:HackyMess.Context="{Binding RelativeSource={RelativeSource Self}}"
         Width="200"
         Margin="5"
         Style="{StaticResource CueBannerTextBoxStyle}" />
<Window.Resources>
  <VisualBrush x:Key="CueBannerBrush"
               AlignmentX="Left"
               AlignmentY="Center"
               Stretch="None">
    <VisualBrush.Visual>
      <Label Content="{Binding Path=(EnhancedControls:CueBannerTextBox.Caption), ElementName=txtProductInterfaceStorageId}"
             Foreground="#4F48DD"
             Background="#B72121"
             Width="200"
             Height="200" />
    </VisualBrush.Visual>
  </VisualBrush>
  <Style x:Key="CueBannerTextBoxStyle"
         TargetType="{x:Type TextBox}">
    <Style.Triggers>
      <Trigger Property="Text"
               Value="{x:Static System:String.Empty}">
        <Setter Property="Background"
                Value="{DynamicResource CueBannerBrush}" />
      </Trigger>
      <Trigger Property="Text"
               Value="{x:Null}">
        <Setter Property="Background"
                Value="{DynamicResource CueBannerBrush}" />
      </Trigger>
      <Trigger Property="IsKeyboardFocused"
               Value="True">
        <Setter Property="Background"
                Value="White" />
      </Trigger>
    </Style.Triggers>
  </Style>
</Window.Resources>