弹出窗口在WPF动画中只显示一次而不再次显示

4
我有一个窗口,在右侧有4个按钮。当我点击其中一个按钮时,我想要显示4个弹出框中的1个。我只完成了第一个,但是我遇到了一个问题,我似乎无法解决。因为这4个弹出框几乎完全相同,所以我决定为ContentControl制作一个模板,然后在其中设置我的内容,并将内容控件放入弹出框中。我的ContentControl模板中的一个项目是关闭按钮。我使用故事板将IsOpen属性设置为false。所以这部分可以正常工作。(这花费了很长时间才解决...)但是当我再次点击该Popup打开同样的弹出框时,它不会显示,我不确定为什么。以下是我的ContentControl模板。
<Style x:Key="PopupContentStyle" TargetType="ContentControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ContentControl">
                <Grid>
                    <Rectangle Fill="WhiteSmoke" Opacity=".50"  Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=Width}" Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=Height}" />
                    <Button Height="50" Style="{DynamicResource CloseButton}" HorizontalAlignment="Right" VerticalAlignment="Top" >
                        <Button.Triggers>
                            <EventTrigger RoutedEvent="Button.Click">
                                <BeginStoryboard>
                                    <Storyboard>
                                        <BooleanAnimationUsingKeyFrames 
                                            Storyboard.Target="{Binding RelativeSource={RelativeSource AncestorLevel=1, AncestorType=Popup,Mode=FindAncestor}}"
                                            Storyboard.TargetProperty="(Popup.IsOpen)" Duration="0:0:0">

                                            <DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="False" />
                                        </BooleanAnimationUsingKeyFrames>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                        </Button.Triggers>
                    </Button>

                    <ContentPresenter />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

尽管这里并不太重要,但是这是我的“弹出窗口”样式:Popup
<Style x:Key="PopupStyle" TargetType="{x:Type Popup}">
    <Setter Property="AllowsTransparency" Value="True"/>
    <Setter Property="PopupAnimation" Value="Fade"/>
    <Setter Property="Placement" Value="Center"/>
    <Setter Property="PlacementTarget" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"/>
</Style>

在我的用户控件中,我有这个弹出窗口:
<Popup x:Name="popuptest" Opened="popuptest_Opened" Closed="popuptest_Opened" Style="{DynamicResource PopupStyle}" >
    <ContentControl Style="{DynamicResource PopupContentStyle}">
        <b:BrightnessControl />
    </ContentControl>
</Popup>

我用来打开亮度按钮的代码并不复杂:

private void brightButton_Click(object sender, RoutedEventArgs e)
{
    popuptest.IsOpen = true;
}

为了保险起见,这是我XAML中的另外两个事件。
public event PopupIsOpenedChangedHandler PopupIsOpenedChanged;
public delegate void PopupIsOpenedChangedHandler(bool isOpen);

private void OnPopupIsOpenedChanged(bool isOpen)
{
    if (PopupIsOpenedChanged != null)
        PopupIsOpenedChanged(isOpen);
}

private void popuptest_Opened(object sender, System.EventArgs e)
{
    OnPopupIsOpenedChanged(popuptest.IsOpen);
}

请帮忙 :). 另外,我现在只用WPF工作了一个月,如果您看到需要改变的地方,请务必建议。谢谢。


1
如果将AutoReverse设置为true会发生什么? - Gayot Fow
@GarryVass 我对你的魔法一无所知 :) 我没有提交我的代码,所以我得等到明天才能测试你说的话。 - Robert Snyder
@GarryVass 我在 BooleanAnimationUsingKeyFrames 中加入了 AutoReverse,但是没有效果。我希望有一种调试方法可以查看发生了什么。 - Robert Snyder
1个回答

4
当动画用于特定属性时,由于优先级列表(link), 进一步的属性分配只能通过动画来实现。引自MSDN
"为了有任何实际效果,属性的动画必须能够优先于基本(未经动画处理的)值,即使该值在本地设置。"
同样出自上述来源:
"对于动画,如果该动画没有为某些行为指定“From”和“To”,或者该动画完成后故意恢复到基本值,则基本值可以影响动画值。要看到这个例子,请运行From、To和By Animation Target Values示例。尝试在示例中设置矩形高度的本地值,以使初始本地值与任何“From”不同。您将注意到动画立即使用“From”值开始,并替换基本值一旦启动。动画可能会指定在完成后返回到动画之前发现的值,方法是指定Stop FillBehavior。之后,基本值确定使用正常优先级。"
因此,动画的属性是首要考虑的内容,然而其他来源,比如代码,不会这样做。
有哪些替代方案? I. 如文档所述,使用FillBehavior="Stop"。由于您没有设置FromToDuration,这对您来说不是一个选项。 II. 在两种情况下都使用EventTrigger
<EventTrigger SourceName="CloseButton" RoutedEvent="Button.Click">
    <BeginStoryboard>
        <Storyboard>
            <BooleanAnimationUsingKeyFrames Storyboard.TargetName="MyPopup"
                                                    Storyboard.TargetProperty="(Popup.IsOpen)" 
                                                    Duration="0:0:0">

                <DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="False" />
            </BooleanAnimationUsingKeyFrames>
        </Storyboard>
    </BeginStoryboard>
</EventTrigger>

<EventTrigger SourceName="OpenButton" RoutedEvent="Button.Click">
    <BeginStoryboard>
        <Storyboard>
            <BooleanAnimationUsingKeyFrames Storyboard.TargetName="MyPopup"
                                                    Storyboard.TargetProperty="(Popup.IsOpen)" 
                                                    Duration="0:0:0">

                <DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True" />
            </BooleanAnimationUsingKeyFrames>
        </Storyboard>
    </BeginStoryboard>
</EventTrigger>

III. 在处理程序(代码中),在设置新值之前,像这样删除动画:

XAML

<Grid>
    <Grid.Triggers>
        <EventTrigger SourceName="CloseButton" RoutedEvent="Button.Click">
            <BeginStoryboard>
                <Storyboard>
                    <BooleanAnimationUsingKeyFrames Storyboard.TargetName="MyPopup"
                                                    Storyboard.TargetProperty="(Popup.IsOpen)" 
                                                    Duration="0:0:0">

                        <DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="False" />
                    </BooleanAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Grid.Triggers>

    <Popup x:Name="MyPopup" Width="200" Height="200" IsOpen="True">
        <Grid Background="Azure">
            <Label Content="Test label" />
        </Grid>
    </Popup>

    <Button Name="OpenButton" Content="OpenButtonFromCode" Width="140" Height="30" Click="OpenButton_Click" />
    <Button Name="CloseButton" Content="CloseButtonfromEventTrigger" Width="180" Height="30" Margin="0,80,0,0" />
</Grid>

代码后台

private void OpenButton_Click(object sender, RoutedEventArgs e)
{
    MyPopup.BeginAnimation(Popup.IsOpenProperty, null);
    MyPopup.IsOpen = true;
}     

1
我最终创建了一个UserControl然后将其从UserControl更改为Popup,添加了我的矩形、按钮和内容呈现器。我制作了一个方法来设置Content Presenter的Child。我使用代码关闭弹出窗口。但这些信息对于未来非常有用,因为我可能会再次这样做。感谢您对此的认真研究。 - Robert Snyder

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