Anche questo mi stava facendo impazzire stasera. Ho creato una ToolTip
sottoclasse per gestire il problema. Per me, su .NET 4.0, la ToolTip.StaysOpen
proprietà non "realmente" rimane aperta.
Nella classe seguente, usa la nuova proprietà ToolTipEx.IsReallyOpen
, invece della proprietà ToolTip.IsOpen
. Otterrai il controllo che desideri. Tramite la Debug.Print()
chiamata, puoi guardare nella finestra di output del debugger quante volte this.IsOpen = false
viene chiamato! Così tanto per StaysOpen
, o dovrei dire "StaysOpen"
? Godere.
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);
}
}
}
Piccolo sproloquio: perché Microsoft non ha reso le DependencyProperty
proprietà (getter / setters) virtuali in modo da poter accettare / rifiutare / modificare le modifiche nelle sottoclassi? O crearne uno virtual OnXYZPropertyChanged
per ognuno DependencyProperty
? Ugh.
---Modificare---
La mia soluzione sopra sembra strana nell'editor XAML: il suggerimento è sempre visualizzato, bloccando del testo in Visual Studio!
Ecco un modo migliore per risolvere questo problema:
Alcuni 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>
Alcuni codici:
// 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);
}
}
Conclusione: c'è qualcosa di diverso nelle classi ToolTip
e ContextMenu
. Entrambi hanno classi "servizio", come ToolTipService
e ContextMenuService
, che gestiscono determinate proprietà, ed entrambi utilizzano Popup
come controllo genitore "segreto" durante la visualizzazione. Infine, ho notato che TUTTI gli esempi di descrizioni comandi XAML sul Web non utilizzano la classe ToolTip
direttamente. Invece, incorporano un StackPanel
con TextBlock
s. Cose che ti fanno dire: "hmmm ..."
ShowDuration
proprietà, pensa che sia qualcosa di simile30,000
. Qualunque cosa maggiore di quello e tornerà automaticamente a5000
.