14

我只是想延迟打开 WPF弹出窗口,有点像ToolTip

我怎样才能做到这一点?

而且,顺便说一句,Popup.PopupAnimation = PopupAnimation.Fade ... 淡入太快了。我想在那里至少半秒钟。

4

5 回答 5

15

您可以通过以下方式创建要应用于 Popup 的样式:

<Style x:Key="TooltipPopupStyle" TargetType="Popup">
    <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:0.25" 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:1" Value="False"/>
                        </BooleanAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </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>

然后,无论何时您想使用它,您都可以编写类似于此的标记(注意 PlacementTarget 的绑定):

<TextBlock x:Name="TargetControl" Text="Hover over me!" />
<Popup PlacementTarget="{Binding ElementName=TargetControl}" Style="{StaticResource TooltipPopupStyle}">
    <Border BorderBrush="Red" BorderThickness="1" Background="White">
        <TextBlock Text="This is a Popup behaving somewhat like the tooltip!" Margin="10" />
    </Border>
</Popup>
于 2010-12-17T20:41:48.487 回答
10

粘贴的答案 cplotts 很好,但可能不适用于您的情况,因为它将动画附加到 IsOpen 属性,有效地将其锁定到位并防止通过直接属性设置、绑定和其他方式对其进行更改。这可能会使您的代码难以使用,具体取决于您使用它的方式。

如果是这种情况,当您想在延迟后打开一个弹出窗口时,我会切换到启动 DispatcherTimer,如下所示:

_popupTimer = new DispatcherTimer(DispatcherPriority.Normal);
_popupTimer.Interval = TimeSpan.FromMilliseconds(100);
_popupTimer.Tick += (obj, e) =>
{
  _popup.IsOpen = true;
};
_popupTimer.Start();

对于类似工具提示的行为,这可以在 MouseEnter 上完成。如果由于某种原因(例如鼠标在弹出窗口出现之前离开控件)要取消弹出窗口打开,只需:

_popupTimer.Stop();

更新

正如评论中观察到的 cplotts 一样,您还需要_popup.IsOpen = false在某些情况下设置 MouseLeave 事件,具体取决于您处理控件和弹出窗口之间的鼠标进入/退出事件的逻辑。请注意,您通常不想盲目地设置IsOpen=false每个 MouseLeave 事件,因为当弹出窗口出现在它上面时它可能会这样做。这在某些情况下会导致闪烁的弹出窗口。所以你需要一些逻辑。

于 2010-01-13T01:56:07.113 回答
8

首先...这个答案的功劳归功于Eric Burke。他回答了发布在 WPF 门徒组中的这个问题。我认为将这个答案也放在 StackOverflow 上会很有用。

基本上,您需要使用 DiscreteBooleanKeyFrame 为 Popup 的 IsOpen 属性设置动画。

查看以下 xaml(可以轻松地将其粘贴到Kaxaml或其他松散的 xaml 编辑实用程序中):

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
    <ContentPresenter>
        <ContentPresenter.ContentTemplate>
            <DataTemplate>
                <Grid>
                    <CheckBox
                        x:Name="cb"
                        Width="100"
                        Height="40"
                        Content="Hover Over Me"
                    />
                    <Popup
                        x:Name="popup"
                        Placement="Bottom"
                        PlacementTarget="{Binding ElementName=cb}"
                    >
                        <Border Width="400" Height="400" Background="Red"/>
                    </Popup>
                </Grid>
                <DataTemplate.Triggers>
                    <Trigger SourceName="cb" Property="IsMouseOver" Value="True">
                        <Trigger.EnterActions>
                            <BeginStoryboard x:Name="bsb">
                                <Storyboard>
                                    <BooleanAnimationUsingKeyFrames
                                        Storyboard.TargetName="popup"
                                        Storyboard.TargetProperty="IsOpen"
                                        FillBehavior="HoldEnd"
                                    >
                                        <DiscreteBooleanKeyFrame KeyTime="0:0:0.5" Value="True"/>
                                     </BooleanAnimationUsingKeyFrames>
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.EnterActions>
                        <Trigger.ExitActions>
                            <StopStoryboard BeginStoryboardName="bsb"/>
                        </Trigger.ExitActions>
                    </Trigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </ContentPresenter.ContentTemplate>
    </ContentPresenter>
</Page>

请注意,我稍微修改了他的原始解决方案......在鼠标悬停时触发 IsOpen,而不是像他一样检查 CheckBox。所有这些都是为了让 Popup 的行为有点像 ToolTip。

于 2010-01-12T20:28:42.763 回答
0
System.Windows.Controls.ToolTip tp = new System.Windows.Controls.ToolTip();

System.Windows.Threading.DispatcherTimer tooltipTimer =
    new System.Windows.Threading.DispatcherTimer
    (
        System.Windows.Threading.DispatcherPriority.Normal
    );

private void TooltipInvalidCharacter()
{
    tp.Content =
        "A flie name cannot contain any of the following character :" +
        "\n" + "\t" + "\\  / : *  ?  \"  <  >  |";

    tooltipTimer.Interval = TimeSpan.FromSeconds(5);
    tooltipTimer.Tick += new EventHandler(tooltipTimer_Tick);
    tp.IsOpen = true;
    tooltipTimer.Start();       
}

void tooltipTimer_Tick(object sender, EventArgs e)
{
     tp.IsOpen = false;
     tooltipTimer.Stop();
}
于 2010-07-20T10:29:50.653 回答
0

您可以为此解决方案扩展 XAML,以便只要鼠标悬停在弹出窗口上,它就会保持打开状态,然后自动消失。

我将示例修改如下:

  1. 创建一个“ClosePopop”动画,在 0.5 秒后将 IsOpen 设置为 False。我把它作为一个资源,因为它被使用了两次。
  2. 对于控件的 IsMouseOver 触发器,添加一个启动 ClosePopup 动画的 ExitAction。这使用户有机会在弹出窗口关闭之前将鼠标移动到弹出窗口上。我将此动画命名为“bxb”
  3. 将触发器添加到弹出窗口的 IsMouseOver 属性。在鼠标悬停时,停止(但不要删除)原始的“bxb” ClosePopup 动画。这使弹出窗口可见;删除此处的动画将使弹出窗口关闭。
  4. 在弹出窗口的 mouseout 上,启动一个新的 ClosePopup 动画,然后删除“bxb”动画。最后一步很关键,否则第一个停止的“bxb”动画将使弹出窗口保持打开状态。

此版本在鼠标悬停时将弹出蓝色变为蓝色,因此您可以使用Kaxaml查看事件序列。

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 <DataTemplate x:Key="TooltipPopup">
  <Grid>
    <CheckBox
        x:Name="cb"
        Width="100"
        Height="40"
        Content="Hover Over Me"/>
    <Popup
        x:Name="popup"
        Placement="Bottom"
        PlacementTarget="{Binding ElementName=cb}">
        <Border x:Name="border" Width="400" Height="400" Background="Red"/>
    </Popup>
  </Grid>
  <DataTemplate.Resources>
    <Storyboard x:Key="ClosePopup">
        <BooleanAnimationUsingKeyFrames
                        Storyboard.TargetName="popup"
                        Storyboard.TargetProperty="IsOpen"
                        FillBehavior="Stop">
            <DiscreteBooleanKeyFrame KeyTime="0:0:0.5" Value="False"/>
        </BooleanAnimationUsingKeyFrames>
    </Storyboard>
  </DataTemplate.Resources>
  <DataTemplate.Triggers>
    <Trigger SourceName="cb" Property="IsMouseOver" Value="True">
        <Trigger.EnterActions>
            <BeginStoryboard x:Name="bsb" >
                <Storyboard>
                    <BooleanAnimationUsingKeyFrames
                        Storyboard.TargetName="popup"
                        Storyboard.TargetProperty="IsOpen"
                        FillBehavior="HoldEnd">
                        <DiscreteBooleanKeyFrame KeyTime="0:0:0.5" Value="True"/>
                    </BooleanAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </Trigger.EnterActions>
        <Trigger.ExitActions>
            <StopStoryboard BeginStoryboardName="bsb"/>
            <BeginStoryboard x:Name="bxb" Storyboard="{StaticResource ClosePopup}"/>
        </Trigger.ExitActions>
    </Trigger>
    <Trigger SourceName="popup" Property="IsMouseOver" Value="True">
        <Setter TargetName="border" Property="Background" Value="Blue"/>
        <Trigger.EnterActions>
            <StopStoryboard BeginStoryboardName="bxb"/>
        </Trigger.EnterActions>
        <Trigger.ExitActions>
            <BeginStoryboard Storyboard="{StaticResource ClosePopup}"/>
            <RemoveStoryboard BeginStoryboardName="bxb"/>
        </Trigger.ExitActions>
    </Trigger>
  </DataTemplate.Triggers>
 </DataTemplate>
</Page>
于 2010-10-03T14:54:33.517 回答