强制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); } }
结论:关于类ToolTip
和ContextMenu
一些不同之处。 两者都具有“服务”类,如ToolTipService
和ContextMenuService
,用于pipe理某些属性,并且在显示期间都将Popup
用作“秘密”父控件。 最后,我注意到Web上的所有 XAML ToolTip示例都不直接使用类ToolTip
。 相反,他们embedded一个StackPanel
与TextBlock
。 事情,让你说:“嗯…”
您可能希望使用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));
它正在为我工作。 将此行复制到您的类构造函数中。