鼠标悬停时使工具提示保持打开状态

时间:2018-07-17 01:01:43

标签: c# wpf vb.net xaml tooltip

我使用.NET 4.0框架在WPF中创建了一个功能区。我正在尝试使用 ToolTipTitle ToolTipDescription ToolTipFooterDescription 。由于我的工具提示将带有超链接,因此如何使它停留在鼠标悬停在工具提示上时?

<rib:RibbonMenuButton ToolTipTitle="Title" ToolTipDescription="My Description" ToolTipFooterDescription="My Footer With a Link">

Microsoft Excel是此功能的一个很好的例子。将鼠标悬停在功能区按钮上时,将向用户显示高级工具提示,并且如果用户将鼠标悬停在工具提示上,它将保持打开状态。我正在尝试模仿该功能。

1 个答案:

答案 0 :(得分:0)

我已经更新了答案,以下是针对我的问题的经过充分测试的解决方案,它将模仿Microsoft Office的工具提示生成:

首先,创建弹出控件:

<Popup x:Class="WPF.Tooltip" AllowsTransparency="True"
       x:Name="TT_Popup_Control"
       xmlns:WPF="clr-namespace:Project_Namespace.WPF"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Project_Namespace"
             mc:Ignorable="d" 
             d:DesignHeight="100" d:DesignWidth="300">
    <Grid>
        <Grid.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="Margin" Value="5" />
                <Setter Property="FontFamily" Value="Sans Serif" />
                <Setter Property="FontSize" Value="11" />
                <Setter Property="TextWrapping" Value="Wrap" />
            </Style>
            <Style TargetType="{x:Type TextBlock}" x:Key="WrappingStyle">
                <Setter Property="TextWrapping" Value="Wrap"/>
            </Style>
        </Grid.Resources>
        <Border BorderBrush="LightGray" BorderThickness="1,1,0,0">
            <Border 
                    BorderThickness="0,0,15,15" 
                    BorderBrush="Transparent"                
                    CornerRadius="0" 
                    Margin="0"
                 >
                <Border.Effect>
                    <DropShadowEffect BlurRadius="10" Opacity="0.8"  ShadowDepth="5" Direction="-40" RenderingBias="Quality" />
                </Border.Effect>
                <StackPanel Background="#efefef">
                    <Grid Margin="5,0,5,0">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*" />
                            <RowDefinition Height="*" />
                            <RowDefinition Height="*" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="1*" />
                            <ColumnDefinition Width="3*" />
                        </Grid.ColumnDefinitions>

                        <!-- Title -->
                        <TextBlock Grid.ColumnSpan="2" Grid.Row="0" FontWeight="Bold" Text="{Binding Title, ElementName=TT_Popup_Control}" />

                        <!-- Description -->
                        <TextBlock Grid.Column="0" Grid.Row="1">
                            <ContentPresenter Content="{Binding Image, ElementName=TT_Popup_Control}" />
                        </TextBlock>
                        <TextBlock Grid.Column="1" Grid.Row="1">
                            <ContentPresenter Content="{Binding Desc, ElementName=TT_Popup_Control}">
                                <ContentPresenter.Resources>
                                    <Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource WrappingStyle}"/>
                                </ContentPresenter.Resources>
                            </ContentPresenter>
                        </TextBlock>
                        <Separator Grid.ColumnSpan="2" Grid.Row="2"  />

                        <!-- Image -->
                        <TextBlock Grid.ColumnSpan="2" Grid.Row="3">
                            <Image Margin="0,0,10,0" Width="16" Source="pack://application:,,,/Path/To/Image/help_icon.png" />
                            <TextBlock Margin="0,-5,0,0">
                                <Hyperlink RequestNavigate="Hyperlink_RequestNavigate" NavigateUri="{Binding Footer, ElementName=TT_Popup_Control}">Tell Me More</Hyperlink>
                            </TextBlock>
                        </TextBlock>
                    </Grid>
                </StackPanel>
            </Border>
        </Border>
    </Grid>
</Popup>

接下来,为该控件创建背后的代码。对于那些想要使用C#等效语言的人,可以前往here。这是我创建控制模板的参考。

Imports System.Windows
Namespace WPF
    Public Class Tooltip
        Public Shared ReadOnly TitleProperty As DependencyProperty = DependencyProperty.Register("Title", GetType(Object), GetType(WPF.Tooltip), New PropertyMetadata(vbNull))
        Public Shared ReadOnly DescProperty As DependencyProperty = DependencyProperty.Register("Desc", GetType(Object), GetType(WPF.Tooltip), New PropertyMetadata(vbNull))
        Public Shared ReadOnly FooterProperty As DependencyProperty = DependencyProperty.Register("Footer", GetType(Object), GetType(WPF.Tooltip), New PropertyMetadata(vbNull))
        Public Shared ReadOnly ImageProperty As DependencyProperty = DependencyProperty.Register("Image", GetType(Object), GetType(WPF.Tooltip), New PropertyMetadata(vbNull))

        Public Property Title As Object
            Get
                Return GetValue(TitleProperty)
            End Get
            Set(value As Object)
                SetValue(TitleProperty, value)
            End Set
        End Property
        Public Property Desc As Object
            Get
                Return GetValue(DescProperty)
            End Get
            Set(value As Object)
                SetValue(DescProperty, value)
            End Set
        End Property
        Public Property Footer As Object
            Get
                Return GetValue(FooterProperty)
            End Get
            Set(value As Object)
                SetValue(FooterProperty, value)
            End Set
        End Property
        Public Property Image As Object
            Get
                Return GetValue(ImageProperty)
            End Get
            Set(value As Object)
                SetValue(ImageProperty, value)
            End Set
        End Property

        Private Sub Hyperlink_RequestNavigate(sender As Object, e As Navigation.RequestNavigateEventArgs)
            System.Diagnostics.Process.Start(e.Uri.ToString())
        End Sub
    End Class
End Namespace

第三步是创建弹出功能,最好通过样式来完成。我将样式创建为资源字典(您可以将其命名为PopupStyle.xaml,但也可以将样式直接嵌入到弹出式xaml控件标记中:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Classic" 
    xmlns:System="clr-namespace:System;assembly=mscorlib">

<Style x:Key="TT_Popup" TargetType="Popup">
        <Setter Property="VerticalOffset" Value="20" />
        <Setter Property="MaxWidth" Value="500" />
        <Setter Property="MinWidth" Value="50" />
        <Style.Triggers>
            <DataTrigger Binding="{Binding PlacementTarget.IsMouseOver, RelativeSource={RelativeSource Self}}" Value="True">
                <DataTrigger.EnterActions>
                    <BeginStoryboard x:Name="OpenPopupStoryBoard" >
                        <Storyboard>
                            <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsOpen" FillBehavior="HoldEnd">
                                <DiscreteBooleanKeyFrame KeyTime="0:0:1.00" Value="True"/>
                            </BooleanAnimationUsingKeyFrames>
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
                <DataTrigger.ExitActions>
                    <PauseStoryboard BeginStoryboardName="OpenPopupStoryBoard"/>
                    <BeginStoryboard x:Name="ClosePopupStoryBoard">
                        <Storyboard>
                            <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsOpen" FillBehavior="HoldEnd">
                                <DiscreteBooleanKeyFrame KeyTime="0:0:0.35" Value="False"/>
                            </BooleanAnimationUsingKeyFrames>
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.ExitActions>
            </DataTrigger>
            <DataTrigger Binding="{Binding PlacementTarget.IsMouseCaptured, RelativeSource={RelativeSource Self}}" Value="True">
                <DataTrigger.EnterActions>
                    <PauseStoryboard BeginStoryboardName="OpenPopupStoryBoard"/>
                    <BeginStoryboard x:Name="CloseImmediatelyPopupStoryBoard" >
                        <Storyboard>
                            <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsOpen" FillBehavior="HoldEnd">
                                <DiscreteBooleanKeyFrame KeyTime="0:0:0.0" Value="False"/>
                            </BooleanAnimationUsingKeyFrames>
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
            <DataTrigger Binding="{Binding PlacementTarget.IsMouseOver, RelativeSource={RelativeSource Self}}" Value="False">
                <DataTrigger.ExitActions>
                    <RemoveStoryboard BeginStoryboardName="CloseImmediatelyPopupStoryBoard" />
                </DataTrigger.ExitActions>
            </DataTrigger>

            <Trigger Property="IsMouseOver" Value="True">
                <Trigger.EnterActions>
                    <PauseStoryboard BeginStoryboardName="ClosePopupStoryBoard" />
                </Trigger.EnterActions>
                <Trigger.ExitActions>
                    <PauseStoryboard BeginStoryboardName="OpenPopupStoryBoard"/>
                    <ResumeStoryboard BeginStoryboardName="ClosePopupStoryBoard" />
                </Trigger.ExitActions>
            </Trigger>
        </Style.Triggers>
    </Style>
</ResourceDictionary>

最后,您必须像这样在Xaml标记中调用新创建的ToolTip控件:

<UserControl xmlns:WPF="clr-namespace:Project_Namespace.WPF"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             >
     <UserControl.Resources>
          <ResourceDictionary.MergedDictionaries>
               <ResourceDictionary Source="PopupStyle.xaml"/>
                    </ResourceDictionary.MergedDictionaries>
               </ResourceDictionary>
     </UserControl.Resources>
     <Grid>
          <Button x:Name="button_name" />

           <!-- Tooltips -->
          <WPF:Tooltip Style="{StaticResource TT_Popup}" PlacementTarget="{Binding ElementName=button_name}">
               <WPF:Tooltip.Title>
                    Tooltip Title
               </WPF:Tooltip.Title>
               <WPF:Tooltip.Image>
                    <Image Source="pack://application:,,,/Path/To/Image.png" />
               </WPF:Tooltip.Image>
               <WPF:Tooltip.Desc>
                    Your Description here
               </WPF:Tooltip.Desc>
               <WPF:Tooltip.Footer>
                    www.example.com
               </WPF:Tooltip.Footer>
          </WPF:Tooltip>
     </Grid>
</UserControl

所以这可能是实现此功能的复杂方法,但是一旦实现,这些工具提示将比默认工具提示好得多,尤其是在需要用户交互时。