1

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

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

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

<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”)获取“工具提示值”值(类型“字符串”)。绑定表达式:路径=(0);DataItem='layoutSettingsViewModel' (HashCode=46457861); 目标元素是'TextBox'(名称='');目标属性是“工具提示”(类型“对象”) InvalidCastException:“System.InvalidCastException:无法将类型“client.Models.layoutSettings.layoutSettingsViewModel”的对象转换为类型“System.Windows.DependencyObject”。

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

无论如何,感谢任何帮助和/或建议。

4

2 回答 2

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

当然,风格等方面还有很多,但我把所有这些都省略了,这样你就只有解决这个问题所需的代码了。

希望这可以帮助某人...

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

于 2013-10-04T19:01:28.997 回答
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">
于 2013-10-03T09:18:15.530 回答