WPF弹出窗口事件处理 - 如何在弹出窗口打开时触发

6

我创建了一个包含网格和边框的WPF弹出窗口。该边框有一些动画效果,我希望每次打开弹出窗口时都会触发这些动画。

目前的代码如下:

<Popup x:Name="myPopUp" >
  <Border x:Name="myBorder" >
    <Border.Triggers>
               <EventTrigger RoutedEvent="Popup.Loaded">
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation
                                    Storyboard.TargetName="myBorder" 
                                    Storyboard.TargetProperty="Height"
                                    From="10" To="255" Duration="0:0:0.20" />                      
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
     </Border.Triggers>
     <Grid />
   </Border>
</Popup>

根据代码,边框在弹出窗口第一次打开时显示动画。我需要做什么改变才能使边框动画每次弹出窗口打开时都触发?

5个回答

7

根据这里给出的建议和一点经验(我在一年前问过这个问题:)),我找到了解决方案。

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525" >
<Window.Resources>
    <Style x:Key="popupStyle" TargetType="{x:Type Popup}" >
        <Style.Triggers>
            <Trigger Property="IsOpen" Value="True">
                <Trigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation
                                Storyboard.TargetProperty="Height"
                                From="10" To="255" Duration="0:0:0.20" />
                        </Storyboard>
                    </BeginStoryboard>
                </Trigger.EnterActions>
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<Grid>
    <Button Width="100" Height="100" Click="Button_Click"></Button>
    <Popup Name="popUp" Width="100" Height="100"  Style="{StaticResource popupStyle}" >
        <Border x:Name="myBorder" Background="Blue"/>
    </Popup>
</Grid>

并且有一个触发弹出窗口的示例代码。

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        popUp.PlacementTarget = (Button)sender;
        popUp.IsOpen = true;
    }

虽然我只能在这里给弹出窗口添加动画效果,而不能对边框进行操作,但它基本上可以产生相同的效果。

1

我不确定弹出窗口在打开时是否会获得焦点,但如果它确实会获得焦点,您可以使用GotFocus事件。或者,您可以尝试在IsOpen属性上使用数据触发器。不过,我认为您需要将其放在样式中而不是内联。


它没有获得焦点。请从您的答案中删除此内容,我会点赞的。 - David

0

你可以通过监听 IsOpen 依赖属性来实现这一点。

    public MainWindow()
    {
        InitializeComponent();

        //// Listening to the IsOpen dependency property of the Popup.
        this.SetBinding(PopupIsOpenProperty, new Binding() { Source = this.popupContainer, Path = new PropertyPath("IsOpen") });
    }

    /// <summary>
    /// Gets or sets a value indicating whether [popup is open].
    /// </summary>
    /// <value><c>true</c> if [popup is open]; otherwise, <c>false</c>.</value>
    public bool PopupIsOpen
    {
        get { return (bool)GetValue(PopupIsOpenProperty); }
        set { SetValue(PopupIsOpenProperty, value); }
    }

    // Using a DependencyProperty as the backing store for PopupIsOpen.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty PopupIsOpenProperty =
        DependencyProperty.Register("PopupIsOpen", typeof(bool), typeof(MainWindow), new PropertyMetadata(false, 
            (dependencyObject, e) =>
            {
                var mainWindow = (MainWindow)dependencyObject;

                if (mainWindow != null &&
                    (bool)e.NewValue == true)
                {
                    //// Raise your event here... like
                    //// mainWindow.RaisePopupOpened();
                    System.Diagnostics.Debug.WriteLine("Popup Open Triggered");
                }
            }));

    private void button_MouseLeave(object sender, MouseEventArgs e)
    {
        this.popupContainer.IsOpen = false;
    }

    private void button_MouseMove(object sender, MouseEventArgs e)
    {
        //// Setting the popup position
        var p = e.GetPosition(sender as UIElement);
        this.popupContainer.HorizontalOffset = p.X;
        this.popupContainer.VerticalOffset = p.Y;

        //// Enabling popup when it is hover on the button
        this.popupContainer.IsOpen = true;
    }


<!-- XAML Starts here-->
<Grid>
    <Button x:Name="button1" Content="This is a sample text" MouseMove="button_MouseMove" MouseLeave="button_MouseLeave" Width="100" Height="25" />
    <Popup x:Name="popupContainer" IsHitTestVisible="False" >
        <Grid Background="White">
            <TextBlock Text="{Binding Content, ElementName=button}" />
        </Grid>
    </Popup>
</Grid>

HTH


这个解决方案对我很有效。尽管我感觉这有点绕弯子了。我想知道是否有一个单行的(或者更小的仅包含XAML的)代码可以解决这个问题。如果在cs代码中实现,意味着我还需要将事件处理程序代码(在这种情况下为边框动画)移到cs文件中。 - Souvik Basu
如果您正在进行代码编写,最好直接在弹出窗口的“Opened”事件上注册。 :) - Oyiwai

0
在 App.xaml.cs 或其他启动类实例中,您需要添加以下内容:
var field = typeof(PresentationSource).GetField("RootSourceProperty", BindingFlags.NonPublic | BindingFlags.Static);
        var property = (DependencyProperty)field.GetValue(null);
        property.OverrideMetadata(typeof(DependencyObject), new FrameworkPropertyMetadata(property.DefaultMetadata.DefaultValue, OnHwndSourceChanged));

在这里,RootSourcePropertyPresentationSource 的私有字段 DependecyProperty。当创建 HwndSource 并设置 RootVisual 时,它的属性被使用。因此,您只需要使用 RootSourceProperty 的属性更改回调即可:

private static void OnHwndSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {

    }

这很好,因为您可以在所有应用程序和所有 HwndSource (PopupWindow 或自定义控件中使用它,在这些控件中使用 HwndSource)


-1
尝试将您的事件触发器更改为:

<EventTrigger RoutedEvent="Popup.Opened">


1
Popup.Opened不是一個路由事件,而是一個普通事件。 - mdm20
我的第一反应是尝试这个,但正如mdm20所提到的,Opened不是路由事件,因此不能在EventTrigger中使用它。但我正在寻找一个像这段代码一样简单的解决方案。 - Souvik Basu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接