Принудительное удержание всплывающей подсказки WPF на экране
у меня есть подсказка для метки, и я хочу, чтобы она оставалась открытой до тех пор, пока пользователь перемещает мышь к другому элементу управления.
Я пробовал следующие свойства в подсказке:
StaysOpen="True"
и
TooltipService.ShowDuration = "60000"
но в обоих случаях подсказка отображается только в течение ровно 5 секунд.
почему эти значения игнорируются?
10 ответов:
просто поместите этот код в раздел инициализации.
ToolTipService.ShowDurationProperty.OverrideMetadata( typeof(DependencyObject), new FrameworkPropertyMetadata(Int32.MaxValue));
TooltipService.ShowDuration работает, но вы должны установить его на объект, имеющий подсказку, например:
<Label ToolTipService.ShowDuration="12000" Name="lblShowTooltip" Content="Shows tooltip"> <Label.ToolTip> <ToolTip> <TextBlock>Hello world!</TextBlock> </ToolTip> </Label.ToolTip> </Label>
Я бы сказал, что этот дизайн был выбран, потому что он позволяет одну и ту же подсказку с разными таймаутами на разных элементах управления.
это было сводит меня с ума Сегодня вечером. Я создал
ToolTip
подкласс для решения проблемы. Для меня, на .Net версии 4.0, тоToolTip.StaysOpen
свойство не "действительно" остается открытым.в классе ниже используйте новое свойство
ToolTipEx.IsReallyOpen
, а не собственностьToolTip.IsOpen
. Вы получите контроль, который вы хотите. ЧерезDebug.Print()
вызов, вы можете посмотреть в окне вывода отладчика, сколько разthis.IsOpen = false
называется! Так много дляStaysOpen
, или я должен сказать"StaysOpen"
? Наслаждаться.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); } } }
небольшая тирада: почему Microsoft не сделала
DependencyProperty
свойства (геттеры/сеттеры) виртуальные, чтобы мы могли принимать/отклонять/корректировать изменения в подклассах? Или сделатьvirtual OnXYZPropertyChanged
для каждогоDependencyProperty
? Тьфу.---редактировать---
мое решение выше выглядит странно в Редакторе XAML - подсказка всегда показывает, блокируя некоторый текст в Visual Studio!
вот лучший способ решить эту проблему:
некоторые 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>
код:
// 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); } }
вывод: что-то другое о классах
ToolTip
иContextMenu
. У обоих есть классы "service", напримерToolTipService
иContextMenuService
, которые управляют определенными свойствами, и оба используютPopup
как" секретный " родительский элемент управления во время отображения. Наконец, я заметил все примеры подсказок XAML в Интернете не используют classToolTip
напрямую. Вместо этого они вставляютStackPanel
СTextBlock
ы. Вещи, которые делают вас скажи: "хммм..."
вы, вероятно, хотите использовать Popup вместо Tooltip, так как Tooltip предполагает, что вы используете его в заранее определенных стандартах пользовательского интерфейса.
Я не уверен, почему StaysOpen не работает,но ShowDuration работает так, как описано в MSDN - это количество времени, когда отображается подсказка. Установите его на небольшое количество (например, 500 мс), чтобы увидеть разницу.
трюк в вашем случае заключается в поддержании состояния "последний зависший контроль", но как только вы это сделаете должно быть довольно тривиально изменять цель размещения и содержимое динамически (вручную или через привязку), если вы используете одно всплывающее окно, или скрывать последнее видимое всплывающее окно, если вы используете несколько.
есть некоторые gotchas с всплывающими окнами до изменения размера и перемещения окна (всплывающие окна не перемещаются с контейнерами), поэтому вы можете также иметь это в виду, пока вы настраиваете поведение. Смотрите этой ссылке для более подробной информации.
НТН.
если вы хотите указать, что только определенные элементы в свой
Window
есть фактически неопределенныйToolTip
продолжительность вы можете определитьStyle
в своемWindow.Resources
для этих элементов. Вот этоStyle
наButton
что такоеToolTip
:<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib" ...> ... <Window.Resources> <Style x:Key="ButtonToolTipIndefinate" TargetType="{x:Type Button}"> <Setter Property="ToolTipService.ShowDuration" Value="{x:Static Member=sys:Int32.MaxValue}"/> </Style> ... </Window.Resources> ... <Button Style="{DynamicResource ButtonToolTipIndefinate}" ToolTip="This should stay open"/> <Button ToolTip="This Should disappear after the default time."> ...
можно также добавить
Style.Resources
доStyle
изменить внешний видToolTip
Это показывает, например:<Style x:Key="ButtonToolTipTransparentIndefinate" TargetType="{x:Type Button}"> <Style.Resources> <Style x:Key="{x:Type ToolTip}" TargetType="{x:Type ToolTip}"> <Setter Property="Background" Value="Transparent"/> <Setter Property="BorderBrush" Value="Transparent"/> <Setter Property="HasDropShadow" Value="False"/> </Style> </Style.Resources> <Setter Property="ToolTipService.ShowDuration" Value="{x:Static Member=sys:Int32.MaxValue}"/> </Style>
Примечание: когда я сделал это, я также использовал
BasedOn
наStyle
так что все остальное определенными для версии моего пользовательского элемента управления с нормальнымToolTip
будет применяться.
я боролся с подсказкой WPF только на днях. Кажется, невозможно остановить его от появления и исчезновения сам по себе, поэтому в конце концов я прибегнул к обработке
Opened
событие. Например, я хотел остановить его от открытия, если у него не было какого-то контента, поэтому я обработалOpened
событие, а затем сделал это:tooltip.IsOpen = (tooltip.Content != null);
это хак, но он работал.
предположительно, вы могли бы также обрабатывать
Closed
событие и сказать ему, чтобы открыть снова, таким образом держа его на виду.
просто для полноты картины: В коде это выглядит так:
ToolTipService.SetShowDuration(element, 60000);
кроме того, если вы когда-нибудь захотите поместить какой-либо другой элемент управления в подсказку, он не будет фокусироваться, так как сама подсказка может получить фокус. Так что, как сказал микатан, ваш лучший выстрел-это всплывающее окно.