WPF:如何在焦点时自动显示我的 ListView 工具提示
WPF: how to auto show my ListView ToolTip when focus
所以我有 ListViewItem
我的对象:
public class ClipboardItem : INotifyPropertyChanged
{
private string _text { get; set; }
public string Text
{
get { return _text; }
set
{
_text = value;
NotifyPropertyChanged();
}
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
和 ToolTip
我想当我的 ListViewItem
IsSelected=True
显示我的 ToolTip
这是我的 ListViewItem
CellTemplate
:
<TextBlock Text="{Binding Path=Text}"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}"
Grid.Column="1"
Margin="5,0,0,0">
<TextBlock.ToolTip>
<ToolTip Content="{Binding Path=Text}"
Placement="Left"
PlacementRectangle="0,0,0,0"
HorizontalOffset="10"
VerticalOffset="20"
HasDropShadow="false"/>
</TextBlock.ToolTip>
</TextBlock>
当我用我的 Up & Down
箭头移动我的 ListViewItem
时,我想自动显示我的 TooTip
而不仅仅是 MouseIsOver
我也尝试在我的 ListViewItem style
:
中删除它
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="False" />
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="True"/>
</MultiDataTrigger.Conditions>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Silver"/>
<Setter Property="BorderThickness" Value="0.5"/>
<Setter Property="ToolTip" Value="{Binding Path=Text}"/>
</MultiDataTrigger>
它们都不起作用,只有在 MouseIsOver
时我才能看到我的 ToolTip
总的来说,这是一个非常糟糕的主意。工具提示有一个非常特殊的行为,这就是为什么 WPF 不像 WinForms 那样方便地公开它 ToolTip.Show
。在这里正确使用的是装饰品。
就是说,如果您绝对坚持手动强制显示工具提示,那么它可以通过行为来完成,但您将不得不捏造一些通常为您处理的功能:
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
namespace YourApp.Behaviors
{
public class ToolTipBehavior : Behavior<FrameworkElement>
{
private ToolTip CurrentToolTip;
public ListViewItem ListViewItem
{
get { return (ListViewItem)GetValue(ListViewItemProperty); }
set { SetValue(ListViewItemProperty, value); }
}
// Using a DependencyProperty as the backing store for ListViewItem. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ListViewItemProperty =
DependencyProperty.Register("ListViewItem", typeof(ListViewItem), typeof(ToolTipBehavior),
new PropertyMetadata(null, (d, e) => (d as ToolTipBehavior)?.OnListViewItemChanged(e)));
private void OnListViewItemChanged(DependencyPropertyChangedEventArgs e)
{
if (e.OldValue is ListViewItem)
(e.OldValue as ListViewItem).Selected -= ToolTipBehavior_Selected;
if (e.NewValue is ListViewItem)
(e.NewValue as ListViewItem).Selected += ToolTipBehavior_Selected;
}
private void ToolTipBehavior_Selected(object sender, RoutedEventArgs e)
{
if (e.Source != e.OriginalSource)
return;
if ((this.ListViewItem != null) && this.ListViewItem.IsSelected)
{
var tooltip = this.AssociatedObject.ToolTip as ToolTip;
if (tooltip != null)
{
if (this.CurrentToolTip != tooltip)
{
if (this.CurrentToolTip != null)
this.CurrentToolTip.Opened -= Tooltip_Opened;
this.CurrentToolTip = tooltip;
if (this.CurrentToolTip != null)
this.CurrentToolTip.Opened += Tooltip_Opened;
}
this.CurrentToolTip.PlacementTarget = this.AssociatedObject;
this.CurrentToolTip.IsOpen = true;
}
}
}
private async void Tooltip_Opened(object sender, RoutedEventArgs e)
{
await Task.Delay(1000);
(this.AssociatedObject.ToolTip as ToolTip).IsOpen = false;
}
}
}
然后你会像这样使用:
<TextBlock Text="{Binding Path=Text}"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}"
Grid.Column="1"
Margin="5,0,0,0">
<i:Interaction.Behaviors>
<behaviors:ToolTipBehavior ListViewItem="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}" />
</i:Interaction.Behaviors>
<TextBlock.ToolTip>
<ToolTip Content="{Binding Path=Text}" ToolTipService.ShowDuration="2"
...etc...
所以我有 ListViewItem
我的对象:
public class ClipboardItem : INotifyPropertyChanged
{
private string _text { get; set; }
public string Text
{
get { return _text; }
set
{
_text = value;
NotifyPropertyChanged();
}
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
和 ToolTip
我想当我的 ListViewItem
IsSelected=True
显示我的 ToolTip
这是我的 ListViewItem
CellTemplate
:
<TextBlock Text="{Binding Path=Text}"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}"
Grid.Column="1"
Margin="5,0,0,0">
<TextBlock.ToolTip>
<ToolTip Content="{Binding Path=Text}"
Placement="Left"
PlacementRectangle="0,0,0,0"
HorizontalOffset="10"
VerticalOffset="20"
HasDropShadow="false"/>
</TextBlock.ToolTip>
</TextBlock>
当我用我的 Up & Down
箭头移动我的 ListViewItem
时,我想自动显示我的 TooTip
而不仅仅是 MouseIsOver
我也尝试在我的 ListViewItem style
:
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="False" />
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="True"/>
</MultiDataTrigger.Conditions>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Silver"/>
<Setter Property="BorderThickness" Value="0.5"/>
<Setter Property="ToolTip" Value="{Binding Path=Text}"/>
</MultiDataTrigger>
它们都不起作用,只有在 MouseIsOver
ToolTip
总的来说,这是一个非常糟糕的主意。工具提示有一个非常特殊的行为,这就是为什么 WPF 不像 WinForms 那样方便地公开它 ToolTip.Show
。在这里正确使用的是装饰品。
就是说,如果您绝对坚持手动强制显示工具提示,那么它可以通过行为来完成,但您将不得不捏造一些通常为您处理的功能:
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
namespace YourApp.Behaviors
{
public class ToolTipBehavior : Behavior<FrameworkElement>
{
private ToolTip CurrentToolTip;
public ListViewItem ListViewItem
{
get { return (ListViewItem)GetValue(ListViewItemProperty); }
set { SetValue(ListViewItemProperty, value); }
}
// Using a DependencyProperty as the backing store for ListViewItem. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ListViewItemProperty =
DependencyProperty.Register("ListViewItem", typeof(ListViewItem), typeof(ToolTipBehavior),
new PropertyMetadata(null, (d, e) => (d as ToolTipBehavior)?.OnListViewItemChanged(e)));
private void OnListViewItemChanged(DependencyPropertyChangedEventArgs e)
{
if (e.OldValue is ListViewItem)
(e.OldValue as ListViewItem).Selected -= ToolTipBehavior_Selected;
if (e.NewValue is ListViewItem)
(e.NewValue as ListViewItem).Selected += ToolTipBehavior_Selected;
}
private void ToolTipBehavior_Selected(object sender, RoutedEventArgs e)
{
if (e.Source != e.OriginalSource)
return;
if ((this.ListViewItem != null) && this.ListViewItem.IsSelected)
{
var tooltip = this.AssociatedObject.ToolTip as ToolTip;
if (tooltip != null)
{
if (this.CurrentToolTip != tooltip)
{
if (this.CurrentToolTip != null)
this.CurrentToolTip.Opened -= Tooltip_Opened;
this.CurrentToolTip = tooltip;
if (this.CurrentToolTip != null)
this.CurrentToolTip.Opened += Tooltip_Opened;
}
this.CurrentToolTip.PlacementTarget = this.AssociatedObject;
this.CurrentToolTip.IsOpen = true;
}
}
}
private async void Tooltip_Opened(object sender, RoutedEventArgs e)
{
await Task.Delay(1000);
(this.AssociatedObject.ToolTip as ToolTip).IsOpen = false;
}
}
}
然后你会像这样使用:
<TextBlock Text="{Binding Path=Text}"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}"
Grid.Column="1"
Margin="5,0,0,0">
<i:Interaction.Behaviors>
<behaviors:ToolTipBehavior ListViewItem="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}" />
</i:Interaction.Behaviors>
<TextBlock.ToolTip>
<ToolTip Content="{Binding Path=Text}" ToolTipService.ShowDuration="2"
...etc...