Esto también me estaba volviendo loco esta noche. Creé una ToolTip
subclase para manejar el problema. Para mí, en .NET 4.0, la ToolTip.StaysOpen
propiedad no "realmente" permanece abierta.
En la siguiente clase, use la nueva propiedad ToolTipEx.IsReallyOpen
, en lugar de la propiedad ToolTip.IsOpen
. Obtendrá el control que desea. A través de la Debug.Print()
llamada, puede ver en la ventana de salida del depurador cuántas veces this.IsOpen = false
se llama. ¿Tanto para StaysOpen
, o debería decir "StaysOpen"
? Disfrutar.
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);
}
}
}
Pequeña perorata: ¿Por qué Microsoft no hizo que las DependencyProperty
propiedades (captadores / definidores) fueran virtuales para que podamos aceptar / rechazar / ajustar cambios en subclases? ¿O hacer una virtual OnXYZPropertyChanged
para todos y cada uno DependencyProperty
? Ugh.
---Editar---
Mi solución anterior se ve extraña en el editor XAML: ¡la información sobre herramientas siempre se muestra, bloqueando parte del texto en Visual Studio!
Aquí hay una mejor manera de resolver este problema:
Algunos 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>
Algún código:
// 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);
}
}
Conclusión: hay algo diferente en las clases ToolTip
y ContextMenu
. Ambos tienen clases de "servicio", como ToolTipService
y ContextMenuService
, que administran ciertas propiedades, y ambos se utilizan Popup
como un control principal "secreto" durante la visualización. Finalmente, noté que TODOS los ejemplos de información sobre herramientas XAML en la Web no usan la clase ToolTip
directamente. En su lugar, incrustan a StackPanel
con TextBlock
s. Cosas que te hacen decir: "hmmm ..."
ShowDuration
propiedad, creo que es algo así30,000
. Cualquier cosa mayor que eso y volverá por defecto a5000
.