如何访问一个Label对象,给定TextBox绑定了它的Content属性

本文关键字:绑定 TextBox 给定 Content 属性 Label 访问 何访问 一个 对象 | 更新日期: 2023-09-27 18:12:47

我的目标是,如果LabelTextBox的内容无效,则将Label的文本包含在错误消息中。在验证过程中,当只有TextBox对象很容易获得时,我希望获得对Label对象的引用,该对象的Target属性绑定到该TextBox

换句话说,给定绑定的,我希望返回或检索该绑定的目标。WPF BindingOperations.GetBindingExpression()和相关方法要求目标对象是已知的。

在WPF XAML中我有这个:

<Label Target="{Binding ElementName=RatingTextBox}">_Rating:</Label>
<TextBox Name ="RatingTextBox"/>

在c#代码中,我尝试了这个:

BindingExpression be = RatingTextBox.GetBindingExpression(TextBox.TextProperty);
string format = be.ParentBinding.StringFormat;

然而,上面的be.ParentBinding是空的,即使我的TextBox肯定受到标签的约束,因为热键"[Alt]-R"有效。我的TextBox可以得到Label的文本不知何故从c#代码背后?

如何访问一个Label对象,给定TextBox绑定了它的Content属性

如果我理解正确,您正在寻找一种方法来自动将TextBoxTooltip属性绑定到TextBox是目标的任何Label对象的Content属性。

不幸的是,要做到这一点最容易,需要WPF中的一种机制,给定绑定的,识别其目标(当然,单个源可以绑定到多个目标)。就我所知,没有这样的机制存在。

但是,我可以想到至少两个不同的替代方案,应该达到类似的效果:

  1. 初始化窗口时,枚举所有的Label对象来找到它们的目标,并相应地更新目标的Tooltip属性。要么显式地设置它们,要么将属性绑定到Label.Content属性。
  2. 反转Label目标声明的方向。也就是说,创建一个可以在TextBox对象上使用的附加属性,指示哪个Label应该针对它。然后使用这个附加属性来初始化Tooltip属性(例如,在附加属性代码中,绑定或设置Tooltip属性,或者有一些其他属性也绑定到附加属性,当它改变时,处理绑定或设置)。

在第二个选项中使用附加属性的动机是允许标签/目标关系在XAML中只声明一次(即避免冗余)。只是声明发生在目标对象(即TextBox)中,而不是标签对象中。

这里有几个例子来说明我的意思& help;

上面第一个选项:

XAML:

<Window x:Class="TestSO32576181BindingGivenSource.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:TestSO32576181BindingGivenSource"
        Title="MainWindow" Height="350" Width="525">
  <StackPanel>
    <StackPanel Orientation="Horizontal">
      <Label x:Name="label1" Content="_Label:" Target="{Binding ElementName=textBox1}"/>
      <TextBox x:Name="textBox1"/>
    </StackPanel>
  </StackPanel>
</Window>
c#

:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        InitTooltips(this);
    }
    private void InitTooltips(FrameworkElement element)
    {
        foreach (FrameworkElement child in
            LogicalTreeHelper.GetChildren(element).OfType<FrameworkElement>())
        {
            Label label = child as Label;
            if (label != null)
            {
                BindingExpression bindingExpression =
                    BindingOperations.GetBindingExpression(label, Label.TargetProperty);
                if (bindingExpression != null)
                {
                    TextBox textBox =
                        FindName(bindingExpression.ParentBinding.ElementName) as TextBox;
                    if (textBox != null)
                    {
                        // You could just set the value, as here:
                        //textBox.ToolTip = label.Content;
                        // Or actually bind the value, as here:
                        Binding binding = new Binding();
                        binding.Source = label;
                        binding.Path = new PropertyPath("Content");
                        binding.Mode = BindingMode.OneWay;
                        BindingOperations.SetBinding(
                            textBox, TextBox.ToolTipProperty, binding);
                    }
                }
            }
            InitTooltips(child);
        }
    }
}


上面第二个选项:

XAML:

<Window x:Class="TestSO32576181BindingGivenSource.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:TestSO32576181BindingGivenSource"
        Title="MainWindow" Height="350" Width="525">
  <StackPanel>
    <StackPanel Orientation="Horizontal">
      <!-- Note that the Target property is _not_ bound in the Label element -->
      <Label x:Name="label1" Content="_Label:"/>
      <!-- Instead, it's specified here via the attached property: -->
      <TextBox x:Name="textBox1" l:TooltipHelper.TargetOf="{Binding ElementName=label1}"/>
    </StackPanel>
  </StackPanel>
</Window>
c#

:

static class TooltipHelper
{
    public static readonly DependencyProperty TargetOfProperty =
        DependencyProperty.RegisterAttached("TargetOf", typeof(Label),
        typeof(TooltipHelper), new PropertyMetadata(null, _OnTargetOfChanged));
    public static void SetTargetOf(FrameworkElement target, Label labelElement)
    {
        target.SetValue(TargetOfProperty, labelElement);
    }
    public static Label GetTargetof(FrameworkElement target)
    {
        return (Label)target.GetValue(TargetOfProperty);
    }
    private static void _OnTargetOfChanged(
        DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        Label oldLabel = (Label)e.OldValue,
            newLabel = (Label)e.NewValue;
        if (oldLabel != null)
        {
            BindingOperations.ClearBinding(oldLabel, Label.TargetProperty);
            BindingOperations.ClearBinding(target, FrameworkElement.ToolTipProperty);
        }
        if (newLabel != null)
        {
            Binding binding = new Binding();
            binding.Source = newLabel;
            binding.Path = new PropertyPath("Content");
            binding.Mode = BindingMode.OneWay;
            BindingOperations.SetBinding(
                target, FrameworkElement.ToolTipProperty, binding);
            binding = new Binding();
            binding.Source = target;
            binding.Mode = BindingMode.OneWay;
            BindingOperations.SetBinding(
                newLabel, Label.TargetProperty, binding);
        }
    }
}

注意,在第二个选项中,不需要在窗口类中添加新代码。它的构造函数可以像往常一样调用InitializeComponent(),仅此而已。所有的代码隐藏都在TooltipHelper类中结束,该类在XAML本身中被引用。