Điều này cũng khiến tôi phát điên tối nay. Tôi đã tạo một ToolTip
lớp con để xử lý vấn đề. Đối với tôi, trên .NET 4.0, ToolTip.StaysOpen
tà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 DependencyProperty
cá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 OnXYZPropertyChanged
cho 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 ToolTip
và ContextMenu
. Cả hai đều có các lớp "dịch vụ", như ToolTipService
và ContextMenuService
, quản lý các thuộc tính nhất định và cả hai đều sử dụng Popup
như 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 ToolTip
trực tiếp. Thay vào đó, họ nhúng a StackPanel
với TextBlock
s. Những điều khiến bạn phải thốt lên: "hmmm ..."
ShowDuration
tà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
.