Как открыть всплывающее окно WPF с задержкой?

Я просто хочу открыть WPF всплывающее окно С задержкой, вроде подсказки.

Как я могу этого достичь?

и, кстати, всплывающее окно.PopupAnimation = PopupAnimation.Увядать... слишком быстро исчезает. Мне нужно хотя бы полсекунды.

5 ответов


вы можете создать стиль для применения к всплывающему окну следующим образом:

<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>

вставленный ответ 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 obseved в комментарии, вы также хотите установить _popup.IsOpen = false в некоторых ситуациях в событии MouseLeave, в зависимости от вашей логики для обработки событий ввода / выхода мыши между вашим элементом управления и всплывающее окно. Имейте в виду, что вы обычно не хотите слепо устанавливать IsOpen=false на каждом событии MouseLeave, потому что он может сделать это, когда всплывающее окно появляется над ним. Это в некоторых ситуациях приведет к мерцающему всплывающему окну. Так что тут нужна логика.


во-первых ... заслуга этого ответа заключается в Эрик Берк. Он!--4-->ответил этот самый вопрос размещен в группе учеников WPF. Я подумал, что было бы полезно поставить этот ответ на StackOverflow тоже.

в основном, вам нужно анимировать свойство IsOpen всплывающего окна с помощью DiscreteBooleanKeyFrame.

Проверьте следующий 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 на мыши по сравнению с проверкой флажка, как у него было. Все в попытке заставить Popup вести себя немного как всплывающая подсказка.


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();
}

вы можете расширить XAML для этого решения, чтобы всплывающее окно оставалось открытым, пока над ним находится мышь, а затем автоматически исчезает.

Я изменил образец следующим образом:

  1. создайте анимацию "ClosePopop", которая устанавливает IsOpen в False через 0,5 секунды. Я сделал этот ресурс, потому что он используется дважды.
  2. для триггера IsMouseOver элемента управления добавьте выход, который запускает анимацию ClosePopup. Это дает пользователю возможность переместить мыши на всплывающее окно, прежде чем она закроется. Я назвал эту анимацию "bxb"
  3. добавьте триггер к свойству ismouseover всплывающего окна. При наведении мыши остановите (но не удаляйте) оригинальную анимацию крупным планом "bxb". Это оставляет всплывающее окно видимым; удаление анимации здесь сделает всплывающее окно закрытым.
  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>