Cela me rendait aussi fou ce soir. J'ai créé une ToolTip
sous - classe pour gérer le problème. Pour moi, sur .NET 4.0, la ToolTip.StaysOpen
propriété n'est pas "vraiment" reste ouverte.
Dans la classe ci-dessous, utilisez la nouvelle propriété ToolTipEx.IsReallyOpen
au lieu de property ToolTip.IsOpen
. Vous obtiendrez le contrôle que vous souhaitez. Via l' Debug.Print()
appel, vous pouvez regarder dans la fenêtre de sortie du débogueur combien de fois this.IsOpen = false
est appelé! Tant pis StaysOpen
, ou devrais-je dire "StaysOpen"
? Prendre plaisir.
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);
}
}
}
Petite diatribe: Pourquoi Microsoft n'a-t-il pas rendu les DependencyProperty
propriétés (getters / setters) virtuelles afin que nous puissions accepter / rejeter / ajuster les changements dans les sous-classes? Ou en faire un virtual OnXYZPropertyChanged
pour chacun DependencyProperty
? Pouah.
---Éditer---
Ma solution ci-dessus semble étrange dans l'éditeur XAML - l'info-bulle est toujours affichée, bloquant du texte dans Visual Studio!
Voici une meilleure façon de résoudre ce problème:
Certains 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>
Un peu de code:
// 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);
}
}
Conclusion: Il y a quelque chose de différent dans les classes ToolTip
et ContextMenu
. Les deux ont des classes "service", comme ToolTipService
et ContextMenuService
, qui gèrent certaines propriétés, et les deux utilisent Popup
comme contrôle parent "secret" pendant l'affichage. Enfin, j'ai remarqué que TOUS les exemples XAML ToolTip sur le Web n'utilisent pas ToolTip
directement la classe . Au lieu de cela, ils intègrent un StackPanel
avec l' TextBlock
art. Des choses qui vous font dire: "hmmm ..."
ShowDuration
propriété, pensez que c'est quelque chose comme30,000
. Tout ce qui est supérieur à cela et il reviendra par défaut5000
.