首页 文章

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

提问于
浏览
103

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

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

StaysOpen="True"

TooltipService.ShowDuration = "60000"

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

为什么忽略这些值?

10 回答

  • 14

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

    <Label ToolTipService.ShowDuration="12000" Name="lblShowTooltip" Content="Shows tooltip">
        <Label.ToolTip>
            <ToolTip>
                <TextBlock>Hello world!</TextBlock>
            </ToolTip>
        </Label.ToolTip>
    </Label>
    

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

  • 8

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

    ToolTipService.ShowDurationProperty.OverrideMetadata(
        typeof(DependencyObject), new FrameworkPropertyMetadata(Int32.MaxValue));
    
  • 5

    这也让我今晚疯狂 . 我创建了一个 ToolTip 子类来处理这个问题 . 对我来说,在.NET 4.0上, ToolTip.StaysOpen 属性不是"really"保持打开状态 .

    在下面的类中,使用新属性 ToolTipEx.IsReallyOpen ,而不是属性 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);
            }
        }
    }
    

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

    • -编辑 - -

    我的解决方案在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>
    

    一些代码:

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

    结论:类 ToolTipContextMenu 有些不同 . 两者都有"service"类,如 ToolTipServiceContextMenuService ,它们管理某些属性,并且在显示期间都使用 Popup 作为"secret"父控件 . 最后,我注意到 ALL Web上的XAML ToolTip示例不直接使用类 ToolTip . 相反,他们将 StackPanelTextBlock 嵌入 . 事情让你说:"hmmm..."

  • 2

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

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

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

    就窗口大小调整和移动而言,弹出窗口有一些问题(弹出窗口需要重新调整行为 . 有关详细信息,请参阅this link .

    HTH .

  • 7

    如果要指定只有 Window 中的某些元素有效地无限期 ToolTip 持续时间,您可以在 Window.Resources 中为这些元素定义 Style . 这是一个 Style for Button ,它有一个 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.">
        ...
    

    也可以将 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>
    

    注意:当我这样做时,我也在 Style 中使用了 BasedOn ,因此将应用为我的自定义控件版本定义的所有其他正常 ToolTip .

  • -4

    前几天我才和WPF Tooltip搏斗 . 它似乎不可能阻止它自己出现和消失,所以最后我采取了处理 Opened 事件 . 例如,我想阻止它打开,除非它有一些内容,所以我处理 Opened 事件,然后这样做:

    tooltip.IsOpen = (tooltip.Content != null);
    

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

    大概你可以类似地处理 Closed 事件并告诉它再次打开,从而保持它可见 .

  • 92

    只是为了完整性:在代码中它看起来像这样:

    ToolTipService.SetShowDuration(element, 60000);
    
  • 0

    此外,如果你想在你的工具提示中放置任何其他控件,它将无法聚焦,因为工具提示本身可以获得焦点 . 所以就像micahtan说的那样,你最好的投篮是Popup .

  • 165

    用相同的代码解决了我的问题 .

    ToolTipService.ShowDurationProperty.OverrideMetadata(typeof(DependencyObject),new FrameworkPropertyMetadata(Int32.MaxValue));

  • 0
    ToolTipService.ShowDurationProperty.OverrideMetadata(
        typeof(DependencyObject), new FrameworkPropertyMetadata(Int32.MaxValue));
    

    它对我有用 . 将此行复制到类构造函数中 .

相关问题