我怎样才能做到这一点?
而且,顺便说一句,Popup.PopupAnimation = PopupAnimation.Fade ... 淡入太快了。我想在那里至少半秒钟。
您可以通过以下方式创建要应用于 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>
粘贴的答案 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 事件,因为当弹出窗口出现在它上面时它可能会这样做。这在某些情况下会导致闪烁的弹出窗口。所以你需要一些逻辑。
首先...这个答案的功劳归功于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。
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,以便只要鼠标悬停在弹出窗口上,它就会保持打开状态,然后自动消失。
我将示例修改如下:
此版本在鼠标悬停时将弹出蓝色变为蓝色,因此您可以使用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>