强制WPF工具提示保留在屏幕上

Tim*_*hyP 111 c# wpf xaml tooltip

我有一个标签的工具提示,我希望它保持打开,直到用户将鼠标移动到另一个控件.

我在工具提示上尝试了以下属性:

StaysOpen="True"
Run Code Online (Sandbox Code Playgroud)

ToolTipService.ShowDuration = "60000"
Run Code Online (Sandbox Code Playgroud)

但在这两种情况下,工具提示仅显示5秒钟.

为什么忽略这些值?

Mar*_*cek 174

TooltipService.ShowDuration 但是你必须在具有Tooltip的对象上设置它,如下所示:

<Label ToolTipService.ShowDuration="12000" Name="lblShowTooltip" Content="Shows tooltip">
    <Label.ToolTip>
        <ToolTip>
            <TextBlock>Hello world!</TextBlock>
        </ToolTip>
    </Label.ToolTip>
</Label>
Run Code Online (Sandbox Code Playgroud)

我之所以选择这种设计是因为它允许在不同的控件上使用相同的工具提示,具有不同的超时.

  • 这应该是选择的答案,因为它是特定于上下文而不是全局的. (9认同)
  • 持续时间以毫秒为单位.默认值为5000.上面的代码指定12秒. (6认同)
  • 它还允许您直接指定`ToolTip`的内容,而无需显式的`<ToolTip>`,这可以使绑定更简单. (4认同)

小智 104

只需将此代码放在初始化部分.

ToolTipService.ShowDurationProperty.OverrideMetadata(
    typeof(DependencyObject), new FrameworkPropertyMetadata(Int32.MaxValue));
Run Code Online (Sandbox Code Playgroud)

  • 我已将此标记(经过将近6年的时间,对不起)作为正确的答案,因为这实际上适用于所有受支持的Windows版本并保持打开49天,这应该足够长:p (6认同)

kev*_*rpe 15

这也让我今晚疯狂.我创建了一个ToolTip子类来处理这个问题.对我来说,在.NET 4.0上,该ToolTip.StaysOpen属性并非"真正"保持开放状态.

在下面的类中,使用new属性ToolTipEx.IsReallyOpen而不是property ToolTip.IsOpen.你会得到你想要的控制.通过Debug.Print()调用,您可以在调试器输出窗口中查看调用的次数this.IsOpen = false!那么多StaysOpen,或者我应该说"StaysOpen"什么?请享用.

public class ToolTipEx : ToolTip
{
    static ToolTipEx()
    {
        IsReallyOpenProperty =
            DependencyProperty.Register(
                "IsReallyOpen",
                typeof(bool),
                typeof(ToolTipEx),
                new FrameworkPropertyMetadata(
                    defaultValue: false,
                    flags: FrameworkPropertyMetadataOptions.None,
                    propertyChangedCallback: StaticOnIsReallyOpenedChanged));
    }

    public static readonly DependencyProperty IsReallyOpenProperty;

    protected static void StaticOnIsReallyOpenedChanged(
        DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        ToolTipEx self = (ToolTipEx)o;
        self.OnIsReallyOpenedChanged((bool)e.OldValue, (bool)e.NewValue);
    }

    protected void OnIsReallyOpenedChanged(bool oldValue, bool newValue)
    {
        this.IsOpen = newValue;
    }

    public bool IsReallyOpen
    {
        get
        {
            bool b = (bool)this.GetValue(IsReallyOpenProperty);
            return b;
        }
        set { this.SetValue(IsReallyOpenProperty, value); }
    }

    protected override void OnClosed(RoutedEventArgs e)
    {
        System.Diagnostics.Debug.Print(String.Format(
            "OnClosed: IsReallyOpen: {0}, StaysOpen: {1}", this.IsReallyOpen, this.StaysOpen));
        if (this.IsReallyOpen && this.StaysOpen)
        {
            e.Handled = true;
            // We cannot set this.IsOpen directly here.  Instead, send an event asynchronously.
            // DispatcherPriority.Send is the highest priority possible.
            Dispatcher.CurrentDispatcher.BeginInvoke(
                (Action)(() => this.IsOpen = true),
                DispatcherPriority.Send);
        }
        else
        {
            base.OnClosed(e);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

小咆哮:为什么微软没有使DependencyProperty属性(getter/setter)成为虚拟,所以我们可以接受/拒绝/调整子类中的更改?或者virtual OnXYZPropertyChanged为每一个做一个DependencyProperty?啊.

- -编辑 - -

我的解决方案在XAML编辑器中看起来很奇怪 - 工具提示总是显示,阻止Visual Studio中的一些文本!

这是解决此问题的更好方法:

一些XAML:

<!-- Need to add this at top of your XAML file:
     xmlns:System="clr-namespace:System;assembly=mscorlib"
-->
<ToolTip StaysOpen="True" Placement="Bottom" HorizontalOffset="10"
        ToolTipService.InitialShowDelay="0" ToolTipService.BetweenShowDelay="0"
        ToolTipService.ShowDuration="{x:Static Member=System:Int32.MaxValue}"
>This is my tooltip text.</ToolTip>
Run Code Online (Sandbox Code Playgroud)

一些代码:

// Alternatively, you can attach an event listener to FrameworkElement.Loaded
public override void OnApplyTemplate()
{
    base.OnApplyTemplate();

    // Be gentle here: If someone creates a (future) subclass or changes your control template,
    // you might not have tooltip anymore.
    ToolTip toolTip = this.ToolTip as ToolTip;
    if (null != toolTip)
    {
        // If I don't set this explicitly, placement is strange.
        toolTip.PlacementTarget = this;
        toolTip.Closed += new RoutedEventHandler(OnToolTipClosed);
    }
}

protected void OnToolTipClosed(object sender, RoutedEventArgs e)
{
    // You may want to add additional focus-related tests here.
    if (this.IsKeyboardFocusWithin)
    {
        // We cannot set this.IsOpen directly here.  Instead, send an event asynchronously.
        // DispatcherPriority.Send is the highest priority possible.
        Dispatcher.CurrentDispatcher.BeginInvoke(
            (Action)delegate
                {
                    // Again: Be gentle when using this.ToolTip.
                    ToolTip toolTip = this.ToolTip as ToolTip;
                    if (null != toolTip)
                    {
                        toolTip.IsOpen = true;
                    }
                },
            DispatcherPriority.Send);
    }
}
Run Code Online (Sandbox Code Playgroud)

结论:课程ToolTip和课程有所不同ContextMenu.两者都有"服务"类,比如ToolTipServiceContextMenuService管理某些属性,并且Popup在显示期间都用作"秘密"父控件.最后,我注意到Web上的所有 XAML ToolTip示例都没有ToolTip直接使用类.相反,它们嵌入一个StackPanel带有TextBlock秒.让你说的话:"嗯......"

  • 你应该因为你的答案的彻底性而获得更多的选票。来自我的 +1。 (2认同)

mic*_*tan 8

您可能希望使用Popup而不是Tooltip,因为Tooltip假定您以预定义的UI标准方式使用它.

我不确定为什么StaysOpen不起作用,但ShowDuration的工作原理如MSDN中所述 - 它是工具提示显示时的显示时间.将其设置为少量(例如500毫秒)以查看差异.

在你的情况下,技巧是保持"最后一个悬停的控制"状态,但是一旦你有了它,如果你使用一个Popup,动态地(手动或通过绑定)更改放置目标和内容应该是相当简单的,如果您使用多个,则隐藏最后一个可见的Popup.

对于窗口大小调整和移动(弹出窗口不随容器移动),弹出窗口有一些问题,因此您可能还想在调整行为时考虑到这一点.有关详细信息,请参阅此链接.

HTH.

  • 还要注意Popup总是位于所有桌面对象之上 - 即使您切换到另一个程序,弹出窗口也会显示并隐藏其他程序的一部分. (3认同)

Jon*_*lan 7

如果您想指定只有您的某些元素Window有效无限期,ToolTip您可以StyleWindow.Resources这些元素中定义一个元素.下面是一个StyleButton有这样的ToolTip:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    ...>
    ...
    <Window.Resources>
        <Style x:Key="ButtonToolTipIndefinate" TargetType="{x:Type Button}">
            <Setter Property="ToolTipService.ShowDuration"
                    Value="{x:Static Member=sys:Int32.MaxValue}"/>
        </Style>
        ...
    </Window.Resources>
    ...
    <Button Style="{DynamicResource ButtonToolTipIndefinate}"
            ToolTip="This should stay open"/>
    <Button ToolTip="This Should disappear after the default time.">
    ...
Run Code Online (Sandbox Code Playgroud)

还可以添加Style.Resources一个Style来改变ToolTip它显示的外观,例如:

<Style x:Key="ButtonToolTipTransparentIndefinate" TargetType="{x:Type Button}">
    <Style.Resources>
        <Style x:Key="{x:Type ToolTip}" TargetType="{x:Type ToolTip}">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="HasDropShadow" Value="False"/>
        </Style>
    </Style.Resources>
    <Setter Property="ToolTipService.ShowDuration"
            Value="{x:Static Member=sys:Int32.MaxValue}"/>
</Style>
Run Code Online (Sandbox Code Playgroud)

注意:当我这样做时,我也使用BasedOnStyle所有为我的自定义控件版本定义的所有其他内容都ToolTip将被应用.


Dan*_*ker 5

前几天我正在和WPF工具提示摔跤.它似乎不可能阻止它自己出现和消失,所以最后我采取了处理Opened事件.例如,我想阻止它打开,除非它有一些内容,所以我处理了Opened事件然后做了这个:

tooltip.IsOpen = (tooltip.Content != null);
Run Code Online (Sandbox Code Playgroud)

这是一个黑客,但它的工作原理.

据推测,您可以类似地处理Closed事件并告诉它再次打开,从而使其可见.