【问题标题】:How Can I Open a WPF Popup with a Delay?如何延迟打开 WPF 弹出窗口?
【发布时间】:2010-01-12 20:20:49
【问题描述】:

我只是想延迟打开 WPF Popup,有点像 ToolTip

我怎样才能做到这一点?

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

【问题讨论】:

    标签: wpf wpf-controls popup delay


    【解决方案1】:

    您可以通过以下方式创建要应用于 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>
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 好点……好主意。您可能还想在上述解决方案中清除 MouseLeave 中的 IsOpen 值。
      • 是的,您可能想要这样做,但要小心。我会更新我的答案来解释我的意思。
      • 雷,非常感谢!这正是我需要的功能。
      【解决方案3】:

      首先......这个答案的功劳归于Eric Burke。他answered 这个问题发布在 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。

      【讨论】:

        【解决方案4】:
        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();
        }
        

        【讨论】:

        • 虽然您的回答根本没有回答问题,但它确实表明您经常希望在一段时间后隐藏工具提示。需要记住的一点。
        【解决方案5】:

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

        我将示例修改如下:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-12-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多