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

时间:2013-10-03 05:49:41

标签: wpf xaml attached-properties

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

所以我创建了一个附加属性来保存工具提示。我将工具提示分配给附加属性,然后使用样式将其复制到tooltip属性。如果出现错误,则样式会将工具提示设置为错误消息。

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

<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>

这看起来相当容易(并且有效)

当错误修复后,我将其设置回来(这不起作用):

<Trigger Property="Validation.HasError"
Value="false">
<Setter Property="ToolTip"
    Value="{Binding Path=(wpfMisc:myCtrl.tooltipValue)}" />
</Trigger>

在xaml文件中我有:

<TextBox Text="this is a textbox with a myMisc based tooltip"
 Name="txtTooltip2"
 wpfMisc:myCtrl.tooltipValue="Tooltip Test tooltip" />

当然,问题很可能出在我的附属财产中,因为看起来信息没有正确保存。这是代码:

public static string GettooltipValue(DependencyObject obj)
{
string value = obj.GetValue(tooltipValueProperty).ToString() ;
value = value.trimNull() ; // extension method to insure at least an empty string
return value ;
}

public static void SettooltipValue(DependencyObject obj, string value)
{
obj.SetValue(tooltipValueProperty, value.trimNull() );
}

public static readonly DependencyProperty tooltipValueProperty =
DependencyProperty.RegisterAttached("tooltipValue",
typeof(string),
typeof(myCtrl),
new UIPropertyMetadata(string.Empty));

所以我的猜测是我需要在UIPropertyMetaData中使用不同的东西,但不确定我会使用什么。或者我的整个方法是错的?

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

我确实通过在错误期间将工具提示移动到标记属性来实现此功能,但我不想让它以这种方式工作,因为我知道当其他一些代码想要使用标记时我会遇到问题以某种特殊的方式。

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

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

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

layoutSettingsViewModel是xaml视图。所以我认为视图本身在某种程度上获得了价值而不是控制......虽然不确定 - 我猜你们其中一个人确切知道它意味着什么以及为什么......我讨厌试图加快速度新语言......

无论如何,任何帮助和/或建议都表示赞赏。

2 个答案:

答案 0 :(得分:0)

我创建了类似的功能,但适用于Button控件。我将为您提供我的工作代码,您只需将Button替换为您要使用的控件。我必须为已禁用的AttachedProperty消息创建一个ToolTip,而另一个用于“记住”原始值:

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);
}

它的用法如下:

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

答案 1 :(得分:0)

对于任何关心的人来说,这里是基本逻辑 - 建立在Sheridan共享的代码之上。我知道这可以更加简洁,等等。但这使得新的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.)
    }
}

当然,风格等等还有很多,但我把所有这些都留下了,所以你只需要解决这个问题所需的代码。

希望这有助于某人...

(如果你认为你可以做得更好,那就去做,想法越多越好)