WPF为工具提示创建附加属性

WPF为工具提示创建附加属性,wpf,xaml,attached-properties,Wpf,Xaml,Attached Properties,我想按预期使用工具提示。但是当发生错误时,我想更改它们以显示错误消息,然后,当错误被修复时,将它们更改回原来的状态 因此,我创建了一个附加属性来保存工具提示。我将工具提示指定给附着的特性,然后使用样式将其复制到工具提示特性。如果出现错误,样式会将工具提示设置为错误消息 因此,在工具提示中设置错误消息的触发器有: <Trigger Property="Validation.HasError" Value="true"> <Setter Proper

我想按预期使用工具提示。但是当发生错误时,我想更改它们以显示错误消息,然后,当错误被修复时,将它们更改回原来的状态

因此,我创建了一个附加属性来保存工具提示。我将工具提示指定给附着的特性,然后使用样式将其复制到工具提示特性。如果出现错误,样式会将工具提示设置为错误消息

因此,在工具提示中设置错误消息的触发器有:

<Trigger Property="Validation.HasError"
                Value="true">
<Setter Property="BorderBrush"
                Value="{DynamicResource controls-errorBorderBrush}" />
<Setter Property="ToolTip"
                Value="{Binding RelativeSource={x:Static RelativeSource.Self},
    Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
所以我猜我需要在UIPropertyMetaData中使用一些不同的东西,但不确定我会使用什么。还是我的整个方法都错了

我想为所有数据字段提供特定于数据的工具提示

我在出错期间将工具提示移动到tag属性,这样做是可行的,但我不想让它保持这种工作方式,因为我知道当其他代码希望以某种特殊方式使用标记时,我最终会遇到问题

另外,我知道有些代码很冗长-只是调试的副作用

myCtrl中的另一个依赖属性工作正常,因此我知道xmlns等引用是正确的

在进一步研究中,我在输出窗口中发现了以下内容: System.Windows.Data错误:17:无法从“”(类型“layoutSettingsViewModel”)获取“tooltipValue”值(类型“String”)。BindingExpression:路径=(0);DataItem='layoutSettingsViewModel'(HashCode=46457861);目标元素是“TextBox”(名称=“”);目标属性为'ToolTip'(类型'Object')InvalidCastException:'System.InvalidCastException:无法将'client.Models.layoutSettings.layoutSettingsViewModel'类型的对象强制转换为'System.Windows.DependencyObject'类型

layoutSettingsViewModel是xaml视图。所以我认为视图本身以某种方式获得了值,而不是控件。。。。但不确定-我猜你们中的一个人确切地知道它的意思和原因。。。我讨厌试图跟上一门新语言的速度


无论如何,任何帮助和/或建议都将不胜感激。

我创建了类似的功能,但用于
按钮
控件。我将为此向您提供我的工作代码,您只需将
按钮
替换为您想要使用的控件即可。我必须为禁用的工具提示创建一个
AttachedProperty
,另一个“记住”原始值:

private static readonly DependencyPropertyKey originalToolTipPropertyKey = DependencyProperty.RegisterAttachedReadOnly("OriginalToolTip", typeof(string), typeof(ButtonProperties), new FrameworkPropertyMetadata(default(string)));

/// <summary>
/// Contains the original Button.ToolTip value to display when the Button.IsEnabled property value is set to true.
/// </summary>
public static readonly DependencyProperty OriginalToolTipProperty = originalToolTipPropertyKey.DependencyProperty;

/// <summary>
/// Gets the value of the OriginalToolTip property.
/// </summary>
/// <param name="dependencyObject">The DependencyObject to return the OriginalToolTip property value from.</param>
/// <returns>The value of the OriginalToolTip property.</returns>
public static string GetOriginalToolTip(DependencyObject dependencyObject)
{
    return (string)dependencyObject.GetValue(OriginalToolTipProperty);
}

/// <summary>
/// Provides Button controls with an additional tool tip property that only displays when the Button.IsEnabled property value is set to false.
/// </summary>
public static DependencyProperty DisabledToolTipProperty = DependencyProperty.RegisterAttached("DisabledToolTip", typeof(string), typeof(ButtonProperties), new UIPropertyMetadata(string.Empty, OnDisabledToolTipChanged));

/// <summary>
/// Gets the value of the DisabledToolTip property.
/// </summary>
/// <param name="dependencyObject">The DependencyObject to return the DisabledToolTip property value from.</param>
/// <returns>The value of the DisabledToolTip property.</returns>
public static string GetDisabledToolTip(DependencyObject dependencyObject)
{
    return (string)dependencyObject.GetValue(DisabledToolTipProperty);
}

/// <summary>
/// Sets the value of the DisabledToolTip property.
/// </summary>
/// <param name="dependencyObject">The DependencyObject to set the DisabledToolTip property value of.</param>
/// <param name="value">The value to be assigned to the DisabledToolTip property.</param>
public static void SetDisabledToolTip(DependencyObject dependencyObject, string value)
{
    dependencyObject.SetValue(DisabledToolTipProperty, value);
}

/// <summary>
/// Adds ro removes event handlers to the Button control that updates the Button.ToolTip value to the DisabledToolTip property value when the Button.IsEnabled property value is set to false.
/// </summary>
/// <param name="dependencyObject">The Button object.</param>
/// <param name="e">The DependencyPropertyChangedEventArgs object containing event specific information.</param>
public static void OnDisabledToolTipChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
    Button button = dependencyObject as Button;
    if (button != null && e.OldValue != e.NewValue) button.IsEnabledChanged += Button_IsEnabledChanged;
    else if (e.OldValue != null && e.NewValue == null) button.IsEnabledChanged -= Button_IsEnabledChanged;
}

private static void Button_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    Button button = sender as Button;
    if (GetOriginalToolTip(button) == null) button.SetValue(originalToolTipPropertyKey, button.ToolTip.ToString());
    button.ToolTip = (bool)e.NewValue ? GetOriginalToolTip(button) : GetDisabledToolTip(button);
}
private static readonly dependencPropertyKey originalToolTipPropertyKey=dependencProperty.RegisterAttachedReadOnly(“OriginalToolTip”、typeof(string)、typeof(ButtonProperties)、new FrameworkPropertyMetadata(默认值(string));
/// 
///包含Button.IsEnabled属性值设置为true时显示的原始Button.ToolTip值。
/// 
public static readonly dependencProperty OriginalToolTipProperty=OriginalToolTipProperty key.dependencProperty;
/// 
///获取OriginalToolTip属性的值。
/// 
///要从中返回OriginalToolTip属性值的DependencyObject。
///OriginalToolTip属性的值。
公共静态字符串GetOriginalToolTip(DependencyObject DependencyObject)
{
返回(字符串)dependencyObject.GetValue(OriginalTooltiProperty);
}
/// 
///为按钮控件提供附加的工具提示属性,该属性仅在Button.IsEnabled属性值设置为false时显示。
/// 
public static DependencyProperty DisabledTooltiProperty=DependencyProperty.RegisterAttached(“DisabledToolTip”、typeof(string)、typeof(ButtonProperties)、new UIPropertyMetadata(string.Empty、OnDisabledToolIPChanged));
/// 
///获取DisabledToolTip属性的值。
/// 
///要从中返回DisabledToolTip属性值的DependencyObject。
///DisabledToolTip属性的值。
公共静态字符串GetDisabledToolTip(DependencyObject DependencyObject)
{
返回(字符串)dependencyObject.GetValue(DisabledTooltiProperty);
}
/// 
///设置DisabledToolTip属性的值。
/// 
///要设置的DisabledToolTip属性值的DependencyObject。
///要分配给DisabledToolTip属性的值。
公共静态void SetDisabledToolTip(DependencyObject DependencyObject,字符串值)
{
SetValue(禁用的工具属性,值);
}
/// 
///将事件处理程序添加到Button控件,当Button.IsEnabled属性值设置为false时,该控件会将Button.ToolTip值更新为DisabledToolTip属性值。
/// 
///按钮对象。
///包含事件特定信息的DependencyPropertyChangedEventArgs对象。
公共静态无效OnDisabledToolIPChanged(DependencyObject DependencyObject,DependencyPropertyChangedEventArgs e)
{
Button Button=作为按钮的dependencyObject;
如果(button!=null&&e.OldValue!=e.NewValue)button.IsEnabledChanged+=button_IsEnabledChanged;
如果(e.OldValue!=null&&e.NewValue==null)button.IsEnabledChanged-=button_IsEnabledChanged;
}
私有静态无效按钮\u IsEnabledChanged(对象发送方,DependencyPropertyChangedEventArgs e)
{
按钮按钮=发送器为按钮;
if(GetOriginalToolTip(button)==null)button.SetValue(originalToolTipPropertyKey,button.ToolTip.ToString());
button.ToolTip=(bool)e.NewValue?GetOriginalToolTip(按钮):GetDisabledToolTip(按钮);
}
它是这样使用的:

<Button ToolTip="Normal ToolTip text to display" 
    Attached:ButtonProperties.DisabledToolTip="Text to automatically display when
    Button is disabled">

对于任何关心此事的人来说,以下是基本逻辑——建立在谢里登共享的代码之上。我知道这可以变得更简洁,等等。但是这使得新的WPF开发人员可以很容易地开始了解事情是如何工作的

以下是xaml样式-可用于支持工具提示和数据的任何控件:

<Style TargetType="TextBox">
<Style.Triggers>
    <Trigger Property="Validation.HasError"
                        Value="true">
        <!-- We have an error, set the ErrorToolTip attached property to
        the error.  When the error is no more, it is automatically set 
        back to the original value (blank) so no need for a 2nd trigger -->
        <Setter Property="wpfMisc:myCtrl.ErrorToolTip"
                        Value="{Binding RelativeSource={x:Static RelativeSource.Self},
      Path=(Validation.Errors)[0].ErrorContent}" />

    </Trigger>

</Style.Triggers>
</Style>

下面是可以添加到包含依赖项属性/属性的类(此处使用myCtrl)中的代码:

/// <summary>
/// Holds the default Tooltip value.  OnMyToolTipChanged used to set ToolTip
/// </summary>
public static DependencyProperty MyToolTipProperty = DependencyProperty.RegisterAttached("MyToolTip", typeof(string), typeof(myCtrl), new UIPropertyMetadata(string.Empty, OnMyToolTipChanged));

/// <summary>
/// Gets the value of the MyToolTip property.
/// </summary>
/// <param name="dependencyObject">The DependencyObject to return the MyToolTip property value from.</param>
/// <returns>The value of the MyToolTip property.</returns>
public static string GetMyToolTip(DependencyObject dependencyObject)
{
    return (string)dependencyObject.GetValue(MyToolTipProperty);
}

/// <summary>
/// Sets the value of the MyToolTip property.
/// </summary>
/// <param name="dependencyObject">The DependencyObject to set the MyToolTip property value of</param>
/// <param name="value">The value to be assigned to the MyToolTip property.</param>
public static void SetMyToolTip(DependencyObject dependencyObject, string value)
{
    dependencyObject.SetValue(MyToolTipProperty, value);
}

/// <summary>
/// Initially blank, set by style when an error occures (or goes away).  Uses OnErrorToolTipChanged to update ToolTip.
/// </summary>
public static DependencyProperty ErrorToolTipProperty = DependencyProperty.RegisterAttached("ErrorToolTip", typeof(string), typeof(myCtrl), new UIPropertyMetadata(string.Empty, OnErrorToolTipChanged));

/// <summary>
/// Gets the value of the ErrorToolTip property.
/// </summary>
/// <param name="dependencyObject">The DependencyObject to return the ErrorToolTip property value from</param>
/// <returns>The value of the ErrorToolTip property.</returns>
public static string GetErrorToolTip(DependencyObject dependencyObject)
{
    return (string)dependencyObject.GetValue(ErrorToolTipProperty);
}

/// <summary>
/// Sets the value of the ErrorToolTip property.
/// </summary>
/// <param name="dependencyObject">The DependencyObject to set the  ErrorToolTip property value of</param>
/// <param name="value">The value to be assigned to the ErrorToolTip property.</param>
public static void SetErrorToolTip(DependencyObject dependencyObject, string value)
{
    dependencyObject.SetValue(ErrorToolTipProperty, value);
}

/// <summary>
/// If an Error Tooltip is supplied, sets the ToolTip to that value, otherwise, resets it back to MyToolTipProperty
/// </summary>
/// <param name="dependencyObject">The control with the tooltip</param>
/// <param name="e">The DependencyPropertyChangedEventArgs object containing event specific information.</param>
public static void OnErrorToolTipChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
    if (dependencyObject is TextBox)
    {
        var txtControl = dependencyObject as TextBox;
        if (e.NewValue == null || e.NewValue.ToString() == string.Empty)
        {
            // No tooltip, reset to the original value
            txtControl.ToolTip = (string)dependencyObject.GetValue(MyToolTipProperty);
        }
        else
        {
            // Use the error tooltip
            txtControl.ToolTip = e.NewValue;
        }
    }
}

/// <summary>
/// This should only be called when the value is first assigned to the control.
/// </summary>
/// <param name="dependencyObject">The Control</param>
/// <param name="e">The DependencyPropertyChangedEventArgs object containing event 
/// specific information.</param>
public static void OnMyToolTipChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
    // What type of control - I may be able to use a generic parent that supports Tooltips, but until I have time to figure that out, using this to generate a valid control.ToolTip reference.
    if (dependencyObject is TextBox)
    {
        var txtControl = dependencyObject as TextBox;
        if (e.OldValue != e.NewValue)
        {
            txtControl.ToolTip = e.NewValue;
        }
    }
    else if (dependencyObject is ComboBox)
    {
        // Add code here for ComboBox and other tooltip controls (if we can't use a parent/interface reference instead.)
    }
}
//
///保存默认的工具提示值。OnMyToolTipChanged用于设置
<Button ToolTip="Normal ToolTip text to display" 
    Attached:ButtonProperties.DisabledToolTip="Text to automatically display when
    Button is disabled">
<Style TargetType="TextBox">
<Style.Triggers>
    <Trigger Property="Validation.HasError"
                        Value="true">
        <!-- We have an error, set the ErrorToolTip attached property to
        the error.  When the error is no more, it is automatically set 
        back to the original value (blank) so no need for a 2nd trigger -->
        <Setter Property="wpfMisc:myCtrl.ErrorToolTip"
                        Value="{Binding RelativeSource={x:Static RelativeSource.Self},
      Path=(Validation.Errors)[0].ErrorContent}" />

    </Trigger>

</Style.Triggers>
</Style>
/// <summary>
/// Holds the default Tooltip value.  OnMyToolTipChanged used to set ToolTip
/// </summary>
public static DependencyProperty MyToolTipProperty = DependencyProperty.RegisterAttached("MyToolTip", typeof(string), typeof(myCtrl), new UIPropertyMetadata(string.Empty, OnMyToolTipChanged));

/// <summary>
/// Gets the value of the MyToolTip property.
/// </summary>
/// <param name="dependencyObject">The DependencyObject to return the MyToolTip property value from.</param>
/// <returns>The value of the MyToolTip property.</returns>
public static string GetMyToolTip(DependencyObject dependencyObject)
{
    return (string)dependencyObject.GetValue(MyToolTipProperty);
}

/// <summary>
/// Sets the value of the MyToolTip property.
/// </summary>
/// <param name="dependencyObject">The DependencyObject to set the MyToolTip property value of</param>
/// <param name="value">The value to be assigned to the MyToolTip property.</param>
public static void SetMyToolTip(DependencyObject dependencyObject, string value)
{
    dependencyObject.SetValue(MyToolTipProperty, value);
}

/// <summary>
/// Initially blank, set by style when an error occures (or goes away).  Uses OnErrorToolTipChanged to update ToolTip.
/// </summary>
public static DependencyProperty ErrorToolTipProperty = DependencyProperty.RegisterAttached("ErrorToolTip", typeof(string), typeof(myCtrl), new UIPropertyMetadata(string.Empty, OnErrorToolTipChanged));

/// <summary>
/// Gets the value of the ErrorToolTip property.
/// </summary>
/// <param name="dependencyObject">The DependencyObject to return the ErrorToolTip property value from</param>
/// <returns>The value of the ErrorToolTip property.</returns>
public static string GetErrorToolTip(DependencyObject dependencyObject)
{
    return (string)dependencyObject.GetValue(ErrorToolTipProperty);
}

/// <summary>
/// Sets the value of the ErrorToolTip property.
/// </summary>
/// <param name="dependencyObject">The DependencyObject to set the  ErrorToolTip property value of</param>
/// <param name="value">The value to be assigned to the ErrorToolTip property.</param>
public static void SetErrorToolTip(DependencyObject dependencyObject, string value)
{
    dependencyObject.SetValue(ErrorToolTipProperty, value);
}

/// <summary>
/// If an Error Tooltip is supplied, sets the ToolTip to that value, otherwise, resets it back to MyToolTipProperty
/// </summary>
/// <param name="dependencyObject">The control with the tooltip</param>
/// <param name="e">The DependencyPropertyChangedEventArgs object containing event specific information.</param>
public static void OnErrorToolTipChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
    if (dependencyObject is TextBox)
    {
        var txtControl = dependencyObject as TextBox;
        if (e.NewValue == null || e.NewValue.ToString() == string.Empty)
        {
            // No tooltip, reset to the original value
            txtControl.ToolTip = (string)dependencyObject.GetValue(MyToolTipProperty);
        }
        else
        {
            // Use the error tooltip
            txtControl.ToolTip = e.NewValue;
        }
    }
}

/// <summary>
/// This should only be called when the value is first assigned to the control.
/// </summary>
/// <param name="dependencyObject">The Control</param>
/// <param name="e">The DependencyPropertyChangedEventArgs object containing event 
/// specific information.</param>
public static void OnMyToolTipChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
    // What type of control - I may be able to use a generic parent that supports Tooltips, but until I have time to figure that out, using this to generate a valid control.ToolTip reference.
    if (dependencyObject is TextBox)
    {
        var txtControl = dependencyObject as TextBox;
        if (e.OldValue != e.NewValue)
        {
            txtControl.ToolTip = e.NewValue;
        }
    }
    else if (dependencyObject is ComboBox)
    {
        // Add code here for ComboBox and other tooltip controls (if we can't use a parent/interface reference instead.)
    }
}