2

一点背景:

我正在构建一个窗口,并且我有一个故事板,用于在用户启动的任务完成后简要显示一个弹出窗口,而无需用户确认。它看起来像这样:

<UserControl.Resources>
    <Storyboard x:Name="FadingFeedback" x:Key="FadingFeedback" Completed="FadingFeedback_Completed">
        <DoubleAnimation  
                         Storyboard.TargetProperty="Opacity" 
                         From="0.5" 
                         To="0" 
                         BeginTime="0:0:0" 
                         Duration="0:0:2.0">
            <DoubleAnimation.EasingFunction>
                <ExponentialEase Exponent="10" EasingMode="EaseIn" />
            </DoubleAnimation.EasingFunction>
        </DoubleAnimation>
    </Storyboard>
</UserControl.Resources>

我正在使用的弹出窗口定义如下:

<Popup Name="popup" Placement="Center" PopupAnimation="Fade" AllowsTransparency="True"
       IsOpen="{Binding DoShowMessage}">
    <Popup.Style>
        <Style>
            <Style.Triggers>
                <DataTrigger Binding="{Binding DoShowMessage}" Value="true">
                    <Setter Property="Popup.IsOpen" Value="true" />
                    <DataTrigger.EnterActions>
                        <BeginStoryboard Storyboard="{StaticResource FadingFeedback}" />
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Popup.Style>
    <Border Background="Black" BorderBrush="White" BorderThickness="1" CornerRadius="5">
        <Grid Background="Transparent">
            <Grid Name="popupGrid" Background="Black" Grid.Column="0" Grid.Row="0" />
            <Label Name="popupLabel" HorizontalAlignment="Center" Foreground="White"
                   VerticalAlignment="Center"
                   Background="Transparent"
                   Grid.Column="0"
                   Grid.Row="0"
               FontSize="16"
               Content="{Binding TextMessage}"/>
        </Grid>
    </Border>
</Popup>

有一个 ViewModel 是它的数据上下文,它有几个属性(在绑定中引用)来提供 TextMessage 字符串和 DoShowMessage 布尔值。它们的定义如下:

    private string _textMessage;
    public string TextMessage
    {
        get { return _textMessage; }
        set
        {
            _textMessage = value;
            OnPropertyChanged("TextMessage");
        }
    }

    private bool _doShowMessage;
    public bool DoShowMessage
    {
        get { return _doShowMessage; }
        set
        {
            _doShowMessage = value;
            OnPropertyChanged("DoShowMessage");
        }
    }

在适当的时候,ViewModel 将设置DoShowMessage属性,XAML 中的绑定将显示弹出窗口并开始情节提要。

现在,我Completed在代码后面的代码中有处理程序,用于执行此操作的弹出窗口:

    void StatusFader_Completed(object sender, EventArgs e)
    {
        popup.IsOpen = false;
    }

并且效果很好,并且由于popup.IsOpen绑定到 ViewModel 上的基础属性DoShowMessage,它将重置该布尔值。

我的问题是:

情节提要完成后,是否有“更好”的方法来处理 DoShowMessage 属性的重置?或者换一种说法,有没有办法在 XAML 本身中做到这一点?我已经阅读了意见/约定,即背后的代码应该(大部分)没有视图代码,但似乎(至少对我而言)这(事件处理程序)是一种合理的方式来做到这一点。想知道是否有办法在 XAML 中做到这一点。

4

1 回答 1

2

是的,当然你可以用另一种方式来做。popup.IsOpen="False"通过设置ObjectAnimationUsingKeyFrames

例如:

Storyboard

<Storyboard x:Name="FadingFeedback" x:Key="FadingFeedback"> 
    <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.5" 
                             To="0" BeginTime="0:0:0" Duration="0:0:2.0">

        <DoubleAnimation.EasingFunction>
            <ExponentialEase Exponent="10" EasingMode="EaseIn" />
        </DoubleAnimation.EasingFunction>
    </DoubleAnimation>

    <ObjectAnimationUsingKeyFrames BeginTime="0:0:2.0" Storyboard.TargetProperty="(Popup.IsOpen)">
        <DiscreteObjectKeyFrame KeyTime="0:0:0">
            <DiscreteObjectKeyFrame.Value>
                <sys:Boolean>False</sys:Boolean>
            </DiscreteObjectKeyFrame.Value>
        </DiscreteObjectKeyFrame>
    </ObjectAnimationUsingKeyFrames>
</Storyboard>

<Popup Name="popup" Placement="Center" PopupAnimation="Fade" AllowsTransparency="True" IsOpen="{Binding DoShowMessage}">
    <Popup.Style>
        <Style>
            <Style.Triggers>
                <DataTrigger Binding="{Binding DoShowMessage}" Value="True">
                <!--<Setter Property="Popup.IsOpen" Value="True" />--> <!-- not necessarily, because we have Popup.IsOpen = True -->

                    <DataTrigger.EnterActions>
                        <BeginStoryboard Storyboard="{StaticResource FadingFeedback}" />
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </Style.Triggers>
            </Style>
    </Popup.Style>  
    ...
</Popup>        

但是在这种情况下,打开Popup外部动画是有问题的,因此动画的属性是第一要务,但是其他来源,例如代码,则不会指定。引用自MSDN

为了产生任何实际效果,属性的动画必须能够优先于基本(未动画)值,即使该值是在本地设置的。

这样可以通过代码访问,从属性中删除动画,从而允许访问属性,如下所示:

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>

Code behind

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

有一个选择,或者只是在事件中popup.IsOpen放入FalseStoryboard_Completed,或者在动画中进行,但是要访问代码,必须将其删除。

对于我自己,我通常这样做,创建一个附加的依赖属性(布尔值),将触发动画绑定到这个属性。如果它的值为真,则启动动画,但要重新运行,以防Storyboard_Completed我不得不将属性折叠为假。就我个人而言,这是一种更简单的方法。

于 2013-08-29T06:31:34.010 回答