我有一个标签的工具提示,我希望它保持打开状态,直到用户将鼠标移动到另一个控件。
我在工具提示上尝试了以下属性:
StaysOpen="True"
和
ToolTipService.ShowDuration = "60000"
但在这两种情况下,工具提示仅显示 5 秒。
为什么这些值会被忽略?
如果您只想为一个工具提示设置此项,请在具有工具提示的对象上设置持续时间,如下所示:
<Label ToolTipService.ShowDuration="12000" Name="lblShowTooltip" Content="Shows tooltip">
<Label.ToolTip>
<ToolTip>
<TextBlock>Hello world!</TextBlock>
</ToolTip>
</Label.ToolTip>
</Label>
我会说选择这种设计是因为它允许在不同控件上具有不同超时的相同工具提示。
如果您希望整个应用程序全局使用此功能,请参阅接受的答案。
只需将此代码放在初始化部分。
ToolTipService.ShowDurationProperty.OverrideMetadata(
typeof(DependencyObject), new FrameworkPropertyMetadata(Int32.MaxValue));
这也让我今晚发疯了。我创建了一个ToolTip
子类来处理这个问题。对我来说,在 .NET 4.0 上,该ToolTip.StaysOpen
属性并非“真正”保持打开状态。
在下面的类中,使用新的属性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
属性(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>
一些代码:
// 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
,并且Popup
在显示期间都用作“秘密”父控件。最后,我注意到Web 上的所有XAML ToolTip 示例都没有ToolTip
直接使用类。相反,他们嵌入了 a StackPanel
with TextBlock
s。让你说:“嗯……”
您可能希望使用 Popup 而不是 Tooltip,因为 Tooltip 假定您以预定义的 UI 标准方式使用它。
我不确定为什么 StaysOpen 不起作用,但 ShowDuration 的工作原理与 MSDN 中的记录一样——它是显示工具提示时显示的时间量。将其设置为少量(例如 500 毫秒)以查看差异。
在您的情况下,诀窍是保持“最后一个悬停控件”状态,但是一旦您拥有它,如果您使用的是一个弹出窗口,动态更改放置目标和内容(手动或通过绑定)应该是相当简单的,或者如果您使用多个,则隐藏最后一个可见的弹出窗口。
就窗口大小调整和移动而言,弹出窗口存在一些问题(弹出窗口不会随容器移动),因此您在调整行为时可能还需要牢记这一点。看此链接。
HTH。
如果您想指定只有您的某些元素Window
具有有效的无限期,您可以在您的这些元素ToolTip
中定义一个。这是一个for有这样一个:Style
Window.Resources
Style
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>
注意:当我这样做时,我还使用BasedOn
了Style
为我的自定义控件版本定义的所有其他内容,ToolTip
并将应用正常。
前几天我还在与 WPF 工具提示搏斗。似乎无法阻止它自己出现和消失,所以最后我求助于处理Opened
事件。例如,我想阻止它打开,除非它有一些内容,所以我处理了这个Opened
事件,然后这样做:
tooltip.IsOpen = (tooltip.Content != null);
这是一个黑客,但它的工作。
大概您可以类似地处理该Closed
事件并告诉它再次打开,从而使其保持可见。
Just for the sake of completeness: In code it looks like this:
ToolTipService.SetShowDuration(element, 60000);
此外,如果您想在 ToolTip 中放置任何其他控件,则它不会成为焦点,因为 ToolTip 本身可以获得焦点。所以就像 micahtan 说的,你最好的镜头是弹出窗口。
用相同的代码解决了我的问题。
ToolTipService.ShowDurationProperty.OverrideMetadata(typeof(DependencyObject), new FrameworkPropertyMetadata(Int32.MaxValue));
ToolTipService.ShowDurationProperty.OverrideMetadata(
typeof(DependencyObject), new FrameworkPropertyMetadata(Int32.MaxValue));
它对我有用。将此行复制到您的类构造函数中。