Điều này cũng khiến tôi phát điên tối nay. Tôi đã tạo một ToolTiplớp con để xử lý vấn đề. Đối với tôi, trên .NET 4.0, ToolTip.StaysOpentài sản không "thực sự" vẫn mở.
Trong lớp dưới đây, sử dụng tài sản mới ToolTipEx.IsReallyOpen, thay vì tài sản ToolTip.IsOpen. Bạn sẽ có được sự kiểm soát mà bạn muốn. Thông qua Debug.Print()cuộc gọi, bạn có thể xem trong cửa sổ Trình gỡ lỗi chỉ số lần this.IsOpen = falseđược gọi! Quá nhiều cho StaysOpen, hoặc tôi nên nói "StaysOpen"? Thưởng thức.
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);
}
}
}
Rant nhỏ: Tại sao Microsoft không biến DependencyPropertycác thuộc tính (getters / setters) thành ảo để chúng ta có thể chấp nhận / từ chối / điều chỉnh các thay đổi trong các lớp con? Hoặc làm virtual OnXYZPropertyChangedcho mỗi và mọi DependencyProperty? Ừ
---Biên tập---
Giải pháp của tôi ở trên có vẻ kỳ lạ trong trình soạn thảo XAML - tooltip luôn hiển thị, chặn một số văn bản trong Visual Studio!
Đây là một cách tốt hơn để giải quyết vấn đề này:
Một số 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>
Một số mã:
// 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);
}
}
Kết luận: Một cái gì đó khác nhau về các lớp ToolTipvà ContextMenu. Cả hai đều có các lớp "dịch vụ", như ToolTipServicevà ContextMenuService, quản lý các thuộc tính nhất định và cả hai đều sử dụng Popupnhư một điều khiển cha "bí mật" trong khi hiển thị. Cuối cùng, tôi nhận thấy TẤT CẢ các ví dụ XAML ToolTip trên Web không sử dụng lớp ToolTiptrực tiếp. Thay vào đó, họ nhúng a StackPanelvới TextBlocks. Những điều khiến bạn phải thốt lên: "hmmm ..."
ShowDurationtài sản, nghĩ rằng nó là một cái gì đó như thế30,000. Bất cứ điều gì lớn hơn thế và nó sẽ mặc định trở lại5000.