WPF StoryBoard仅在首次呼叫时触发

时间:2014-03-27 17:53:12

标签: c# wpf storyboard

我一直试图在控件中显示一条消息,当我收到一条消息说我已经成功收到我发布的更新时,该消息只会出现几秒钟。

我有一个实现INotifyPropertyChanged的类,如下所示:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace Wpf.GUI.Views
{
public class AlertBarStatus : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public event RoutedEventHandler VisibleChanged;

    private bool _visible ;
    private bool _success ;

    public AlertBarStatus():this (false,false)
    {

    }


    public AlertBarStatus(bool visible, bool success)
    {
        _visible = visible;
        _success = success;
    }


    public bool Visible
    {
        get { return _visible; }
        set
        {
            _visible = value;
            OnPropertyChanged("Visible");

            if(VisibleChanged != null)
            {
                VisibleChanged(this, null);
            }
        }
    }

    public bool Success
    {
        get { return _success; }
        set
        {
            _success = value;
            OnPropertyChanged("Success");
        }
    }


    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}
}

我有xaml,其中包含如下控件:

<UserControl x:Class="Wpf.GUI.AlertBarControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
         DataContext="{Binding RelativeSource={RelativeSource Self}}"
         >
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>
    <Border x:Name="alertStatusBorder" Height="50" Visibility="Collapsed" Opacity="0" HorizontalAlignment="Stretch" >
        <Border.Style>
            <Style TargetType="Border">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding AlertBarStatus.Success}" Value="True">
                        <Setter Property="Background" Value="{StaticResource EnabledBorderBackground}" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding AlertBarStatus.Success}" Value="False">
                        <Setter Property="Background" Value="{StaticResource DisabledBorderBackground}" />
                    </DataTrigger>

                    <DataTrigger x:Name="VisibilityTrigger" Binding="{Binding AlertBarStatus.Visible}" Value="True">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard x:Name="VisibilityStoryboard">
                                    <ObjectAnimationUsingKeyFrames Duration="0:0:0" Storyboard.TargetProperty="(UIElement.Visibility)">
                                        <DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <DoubleAnimation Storyboard.TargetProperty="Opacity"
                                 From="0" To="100" Duration="0:0:5" />
                                    <DoubleAnimation Storyboard.TargetProperty="Opacity"
                                 From="100" To="0" Duration="0:0:5" />
                                    <ObjectAnimationUsingKeyFrames Duration="0:0:5" Storyboard.TargetProperty="(UIElement.Visibility)">
                                        <DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                        <DataTrigger.ExitActions>
                            <StopStoryboard BeginStoryboardName="VisibilityStoryboard"/>
                        </DataTrigger.ExitActions>
                    </DataTrigger>



                </Style.Triggers>
            </Style>
        </Border.Style>
        <DockPanel >
            <TextBlock DockPanel.Dock="Left" x:Name="alertStatusText" Grid.Column="0" HorizontalAlignment="Left">
                <TextBlock.Style>
                    <Style TargetType="TextBlock">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding AlertBarStatus.Success}" Value="True">
                                <Setter Property="Text" Value="Successfully published updates" />
                            </DataTrigger>
                            <DataTrigger Binding="{Binding AlertBarStatus.Success}" Value="False">
                                <Setter Property="Text" Value="Failed to publish updates" />
                            </DataTrigger>
                        </Style.Triggers>
                        <Setter Property="FontSize" Value="20"></Setter>
                        <Setter Property="VerticalAlignment" Value="Center"></Setter>
                    </Style>
                </TextBlock.Style>
            </TextBlock>
            <!--<Button Height="20" Width="20" Margin="3" DockPanel.Dock="Right" HorizontalAlignment="Right" 
                    Background="Transparent" BorderBrush="Black"
                    Click="CloseAlertControl_Click">X</Button>-->
        </DockPanel>

    </Border>

</Grid>

名为VisibilityTrigger的DataTrigger完全符合我的要求,但仅当Success值第一次更改时才会执行。它不会再被调用。

我知道这个问题有几个不同的答案,但我已经尝试了所有可以找到的解决方案,但到目前为止,它们都不适用于我。

为了澄清,可见性属性可以在设置为false之前多次设置为true,因此我认为这可能是问题,因为我没有将值设置为不同的值,但我可以看到正在调用OnProperty更改的方法,所以我不希望这是一个问题。

对此有任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

最后,我放弃尝试在xaml中执行此操作,而只是将对象可见性绑定到我的基础对象的可见性属性,如下所示。

<Border x:Name="alertStatusBorder" Height="50" Visibility="{Binding Path=AlertBarStatus.Visible, Converter={StaticResource BoolToVis}}">

然后我使用了一个带有事件的计时器,该事件在10秒后触发,将可见性变量设置为false,并禁用像魅力一样工作的计时器。

计时器代码:

Timer _alertBarTimer = new Timer(10000);
_alertBarTimer.Elapsed += _alert_timer_elapsed;

private void _alert_timer_elapsed(object sender, ElapsedEventArgs e)
{
    alertBarControl.AlertBarStatus.Visible = false;
    _alertBarTimer.Enabled = false;
}

设置可见性的代码:

alertBarControl.AlertBarStatus.Visible = true;
_alertBarTimer.Enabled = true;

这可能不是最好的方法,但它肯定不是最糟糕的,因为我没有直接在代码中设置控件的属性,而是使用绑定到控件的对象。

如果有人有更好的方法,请随时提供:)