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

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

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

StaysOpen="True" 

 TooltipService.ShowDuration = "60000" 

但是在这两种情况下,工具提示只显示5秒钟。

为什么这些值被忽略?

只需把这个代码放在初始化部分。

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

TooltipService.ShowDuration可以工作,但是您必须将其设置在具有Tooltip的对象上,如下所示:

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

我会说这个devise被选中是因为它允许在不同的控件上使用不同的超时时间。

这也是今晚让我疯狂的。 我创build了一个ToolTip子类来处理这个问题。 对我来说,在.NET 4.0上, ToolTip.StaysOpen属性并不是“真的”保持打开状态。

在下面的类中,使用新的属性ToolTipEx.IsReallyOpen ,而不是属性ToolTip.IsOpen 。 你会得到你想要的控制。 通过Debug.Print()调用,您可以在debugging器输出窗口中看到this.IsOpen = false被调用了多less次! 对于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 / setter)虚拟,所以我们可以接受/拒绝/调整子类的变化? 或者为每个DependencyProperty创build一个virtual OnXYZPropertyChanged ? 啊。

– -编辑 – –

上面的解决scheme在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一些不同之处。 两者都具有“服务”类,如ToolTipServiceContextMenuService ,用于pipe理某些属性,并且在显示期间都将Popup用作“秘密”父控件。 最后,我注意到Web上的所有 XAML ToolTip示例都不直接使用类ToolTip 。 相反,他们embedded一个StackPanelTextBlock 。 事情,让你说:“嗯…”

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

我不确定为什么StaysOpen不起作用,但是ShowDuration的工作方式与MSDN中logging的一样 – 这是显示工具提示时的显示时间。 将其设置为less量(例如500毫秒)以查看差异。

在你的情况下,诀窍是保持“最后一个控制”状态,但是如果你使用的是一个popup窗口,则应该相当简单地dynamic地更改放置目标和内容(手动或通过绑定)或者如果你使用多个隐藏最后一个可见的Popup。

对于popup窗口,有一些小问题,就像窗口大小调整和移动一样(Popups不会移动容器),所以当你调整行为的时候,你可能也想记住这一点。 看到这个链接了解更多细节。

HTH。

那天我只是在和WPF Tooltip搏斗。 似乎不可能阻止它自己出现和消失,所以最终我采取了处理Opened事件。 例如,我想阻止它开放,除非它有一些内容,所以我处理了Opened事件,然后做到这一点:

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

这是一个黑客,但它的工作。

据推测,你可以类似的处理Closed事件,并告诉它再次打开,从而保持可见。

如果你想指定只有你的Window某些元素具有有效的无限期ToolTip持续时间,你可以在你的Window.Resources为这些元素定义一个Style 。 这是一个带有这样的ToolTip Button Style

 <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为我的自定义控件的版本定义的所有东西都会被应用。

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

 ToolTipService.SetShowDuration(element, 60000); 

另外,如果你想把任何其他控件放在你的工具提示中,它将不会被集中,因为工具提示本身可以获得焦点。 所以就像micahtan说的那样,你最好的拍摄是Popup。

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

它正在为我工​​作。 将此行复制到您的类构造函数中。