Search code examples
wpfpopupwpfdatagrid

Open Popup with delay when clicking cell


I want to show a popup with delay 2 seconds always when any cell of a column is selected and the cursor stays longer than 2 seconds. I could implement that with timers and eventhandlers but I think,I can also achieve that with storyboards. I try to do that so:

<Window x:Class="Wpfpopupstoryboard.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">

<Window.Resources>
    <Storyboard x:Key="ShowPopup">
        <BooleanAnimationUsingKeyFrames Storyboard.TargetName="LockPopup" Storyboard.TargetProperty="(Popup.IsOpen)">
            <DiscreteBooleanKeyFrame KeyTime="00:00:02.0" Value="True" />
        </BooleanAnimationUsingKeyFrames>
    </Storyboard>

    <Storyboard x:Key="HidePopup" Storyboard.TargetName="LockPopup" Storyboard.TargetProperty="(Popup.IsOpen)">
        <BooleanAnimationUsingKeyFrames>
            <DiscreteBooleanKeyFrame KeyTime="00:00:00.1" Value="False" />
        </BooleanAnimationUsingKeyFrames>
    </Storyboard>
</Window.Resources>

<Grid x:Name="LayoutRoot">
    <DataGrid Name="MyGrid" xmlns:sys="clr-namespace:System;assembly=mscorlib" IsReadOnly="True">
        <DataGrid.Resources>
            <Style TargetType="DataGridCell">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="DataGridCell">
                            <StackPanel>
                                <Border x:Name="border"
                            BorderThickness="2"
                            BorderBrush="Silver">
                                    <ContentPresenter Name="MyContentPresenter" Content="{Binding}"/>

                                </Border>
                                <Popup x:Name="LockPopup" PlacementTarget="{Binding ElementName=MyContentPresenter}" Placement="Bottom"  DataContext="{Binding}">
                                    <TextBlock Text="This is a popup" Background="White" Foreground="Black" />
                                </Popup>
                            </StackPanel>

                            <ControlTemplate.Triggers>
                                <EventTrigger RoutedEvent="StackPanel.MouseLeftButtonDown">
                                    <BeginStoryboard Storyboard="{StaticResource ShowPopup}"/>
                                </EventTrigger>
                                <EventTrigger RoutedEvent="StackPanel.MouseLeave">
                                    <BeginStoryboard Storyboard="{StaticResource HidePopup}"/>
                                </EventTrigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </DataGrid.Resources>
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding}" Header="column" />
        </DataGrid.Columns>
        <sys:String>item 1</sys:String>
        <sys:String>item 2</sys:String>
        <sys:String>item 3</sys:String>
        <sys:String>item 4</sys:String>
    </DataGrid>
</Grid>

What is wrong? Can somebody help me?

Thank you!


Solution

  • With using RemoveStoryboard action, you need just 1 Storyboard (to show the popup). Also the right event to trigger the Storyboard here is Selected instead of StackPanel.MouseLeftButtonDown:

    <ControlTemplate.Triggers>
       <EventTrigger RoutedEvent="Selected">
          <BeginStoryboard Storyboard="{StaticResource ShowPopup}" Name="bg"/>
       </EventTrigger>
       <EventTrigger RoutedEvent="MouseEnter">
          <BeginStoryboard Storyboard="{StaticResource ShowPopup}" Name="bg2"/>
       </EventTrigger>
       <EventTrigger RoutedEvent="MouseLeave">
          <RemoveStoryboard BeginStoryboardName="bg"/>
       </EventTrigger>
    </ControlTemplate.Triggers>
    

    You can delete the HidePopup Storyboard, because we don't need it with the code above.

    In fact you can also use StackPanel.PreviewMouseLeftButtonDown, somehow the StackPanel.MouseLeftButtonDown is suppressed (while bubbling up from the inner elements). However it's just a bit explanation about why it's not working at first. Using the Selected event is the best choice.