Как я могу открыть всплывающее окно WPF с задержкой? - PullRequest
13 голосов
/ 12 января 2010

Я просто хочу открыть WPF Popup с задержкой, вроде ToolTip .

Как мне этого добиться?

И, кстати, Popup.PopupAnimation = PopupAnimation.Fade ... слишком быстро исчезает. Я хочу там хотя бы полсекунды.

Ответы [ 5 ]

12 голосов
/ 17 декабря 2010

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

<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>
10 голосов
/ 13 января 2010

Вставленный ответ 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, потому что это может быть сделано, когда над ним появляется всплывающее окно. В некоторых ситуациях это может привести к вспыхивающему всплывающему окну. Так что вам понадобится немного логики.

8 голосов
/ 12 января 2010

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

0 голосов
/ 03 октября 2010

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

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

  1. Создать анимацию «ClosePopop», которая устанавливает значение IsOpen в False через 0,5 секунды. Я сделал это ресурсом, потому что он используется дважды.
  2. Для триггера IsMouseOver элемента управления добавьте действие ExitAction, которое запускает анимацию ClosePopup. Это дает пользователю возможность навести курсор мыши на всплывающее окно до его закрытия. Я назвал эту анимацию "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>
0 голосов
/ 20 июля 2010
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();
}
...