【问题标题】:Bind to wpf custom control dependency property for tooltip?绑定到工具提示的wpf自定义控件依赖属性?
【发布时间】:2014-06-10 12:44:50
【问题描述】:

我有一个我在 WPF 中编写的自定义控件,它有一个布尔依赖属性:

public static readonly DependencyProperty IsAlertProperty
    = DependencyProperty.Register("IsAlert", typeof(bool), typeof(AlertControl),
        new FrameworkPropertyMetadata(default(bool),
            FrameworkPropertyMetadataOptions.None,
            OnIsAlertChanged,
            null,
            false,
            UpdateSourceTrigger.PropertyChanged));

public bool IsAlert
{
    get { return (bool)GetValue(IsAlertProperty); }
    set { SetValue(IsAlertProperty, value); }
}

在我的 Generic.xaml 中,我有以下 xaml 代码:

<Style TargetType="{x:Type local:AlertControl}">
    <Setter Property="Template">
        <Setter.Value> ... </Setter.Value>
    </Setter>

    <Setter Property="ToolTip">
        <Setter.Value>
            <ToolTip Visiblity="{Binding Path=IsAlert,
                             RelativeSource={RelativeSource TemplatedParent},
                             Converter={StaticResource BooleanToVisiblityConverter}">
                <!-- Tooltip content goes here -->
            </ToolTip>
        </Setter.Value>
    </Setter>
<Style />

问题是这似乎不起作用。我使用 Snoop 监视我的 xaml,IsAlert 属性正在适当更改,但如果我深入研究我的AlertControl.ToolTip,我发现Visiblity DependencyProperty 有绑定错误。我也尝试使用RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:AlertControl}},但这也带来了绑定问题。我不知道如何诊断这个,因为我的输出窗口也没有吐出任何绑定表达式错误。

【问题讨论】:

    标签: c# wpf xaml custom-controls dependency-properties


    【解决方案1】:

    当涉及到 WPF ToolTip 时,您必须了解它不是 VisualTree 的一部分,就像其他控件一样。它仅在需要创建它时发挥作用,即当您的鼠标悬停在控件上时。此时,WPF 会创建ToolTip,但不会将其作为AlertControl 的子元素,这就是RelativeSourceModes(TemplatedParentFindAncestor)都不起作用的原因.

    不过有一个可取之处,那就是 ToolTip.PlacementTarget 属性。

    <ToolTip Visibility="{Binding Path=PlacementTarget.(local:AlertControl.IsAlert),
                                  RelativeSource={RelativeSource Self},
                                  Converter={...}}">
        ...
    <ToolTip>
    

    您在这里所做的是告诉 WPF BindingExtension 绑定到名为 PlacementTarget 的属性(这恰好是创建 ToolTipUIElement,在您的情况下是 AlertControl),并且您说要从ToolTip 本身(不是ToolTipDataContext)定位此属性。除此之外,您还计划使用IValueConverter。此外,完整未解析的PropertyInfo不仅在ToolTip上查找PlacementTarget,而且还检查从PlacementTarget返回的对象是否可以转换为AlertControl的类型,然后访问其IsAlert CLR 属性。我本可以轻松完成Path=PlacementTarget.IsAlert,并且通过反射,它会很好地工作,但我更愿意明确声明应该从AlertControl 类型访问IsAlert 属性。

    【讨论】:

    • 谢谢!这非常有效。我从来不知道工具提示不是在我的警报控制下创建的。
    【解决方案2】:

    您是否也将变量添加到代码隐藏中?

    喜欢:

    public bool IsAlert
        {
            get { return (bool)GetValue(IsAlertProperty); }
            set { SetValue(IsAlertProperty, value); }
        }
    

    使用它应该允许您在没有任何层次信息的情况下绑定它。顺便说一句,您可以通过在转换器中设置断点轻松检查您的绑定是否正常工作。

    【讨论】:

    • @Sheridan:实际上,WPF BindingExtension 包含一个名为Path 的属性,它恰好是PropertyInfo。它使用PropertyInfo 和反射来获取CLR 属性的值,而不管该属性是如何实现的。 DependencyProperty 只是实现 CLR 属性的一种方式,这将允许它自动处理属性值验证、强制和更改通知,并提供在动画等中使用的能力。所以,你显然完全不知道你在说什么。
    • @Sheridan:给出的答案是有效的,尽管不正确,但考虑到 OP 从问题中遗漏了 CLR 属性这一事实,尝试回答该问题。因此,认为也许这就是缺失的东西是有道理的。但是,关于不需要 CLR 属性的评论显然是 100% 错误的。整个 WPF 绑定引擎通过 CLR 属性工作,它可能不太关心该属性是如何实际实现的,只要它提供具有公共访问权限的必要 get(和可选 set)方法。
    • @Sheridan:sigh,如果我只能对你的 cmets 投反对票的话。无论如何,相信你想相信的东西(即使它是 100% 错误的),但接受你错了的事实并继续前进。
    【解决方案3】:

    编写CustomControl 与创建基本UserControl 不同。首先,您没有自己的 XAML 文件来定义您的控件……您必须共享 generic.xaml 文件。当涉及到数据绑定或事件处理时,这通常会导致新的开发人员出现问题。不过,解决方法很简单。

    您需要做的就是使用RelativeSource Binding,而不是TemplatedParent,而是您的 控件的属性。试试这个:

    <ToolTip Visiblity="{Binding Path=IsAlert, RelativeSource={RelativeSource 
        AncestorType={x:Type YourXamlNamespacePrefix:AlertControl}}, 
        Converter={StaticResource BooleanToVisiblityConverter}">
        <!-- Tooltip content goes here -->
    </ToolTip>
    

    【讨论】:

    • 我已经尝试使用AncestorType 模式,但没有成功。我使用 Snoop 工具检查发生了什么,我发现绑定表达式有问题。此外,我推出了自己的转换器,因此我可以在其中放置一个断点,该断点适用于其他代码区域,但不适用于此控件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-29
    • 2010-12-27
    • 2019-05-26
    • 1970-01-01
    • 2012-08-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多