Mike
Mike

Reputation: 6239

How to animate background colour when label value changes

I'm trying to get a label to change background colour when the value it's bound to changes. If it goes up, flash green temporarily. If it goes down, flash red temporarily.

When I launch the app I get these issues:

Can anyone see what's wrong with this please and also comment on a better way to structure this? I'm wondering if there's a better way to determine if the value has gone up or down without needing 6 properties on the ViewModel for bid, ask and spread? I'm also wondering if it's up to very frequent change of values (say 5+ per second)?

Thanks.


View

<Window x:Class="TestApp.UI.View.QuoteView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="QuoteView" Height="300" Width="300">
    <Window.Resources>
        <Style x:Key="BidStyle">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=BidHigher}" Value="True">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetProperty="Background.Color" To="Green" Duration="0:0:0.2" AutoReverse="True"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=BidLower}" Value="True">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetProperty="Background.Color" To="Red" Duration="0:0:0.2" AutoReverse="True"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=AskHigher}" Value="True">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetProperty="Background.Color" To="Green" Duration="0:0:0.2" AutoReverse="True"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=AskLower}" Value="True">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetProperty="Background.Color" To="Red" Duration="0:0:0.2" AutoReverse="True"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=SpreadHigher}" Value="True">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetProperty="Background.Color" To="Green" Duration="0:0:0.2" AutoReverse="True"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=SpreadLower}" Value="True">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetProperty="Background.Color" To="Red" Duration="0:0:0.2" AutoReverse="True"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <Label Content="Bid" HorizontalAlignment="Left" Margin="21,10,0,0" VerticalAlignment="Top" />
        <Label Content="Ask" HorizontalAlignment="Left" Margin="19,53,0,0" VerticalAlignment="Top"/>
        <Label Content="Spread" HorizontalAlignment="Left" Margin="19,99,0,0" VerticalAlignment="Top"/>
        <Label x:Name="BidLabel" HorizontalAlignment="Left" Margin="102,10,0,0" VerticalAlignment="Top" Content="{Binding Path=Quote.Bid}" Style="{StaticResource ResourceKey=BidStyle}"/>
        <Label x:Name="AskLabel" HorizontalAlignment="Left" Margin="102,53,0,0" VerticalAlignment="Top" Content="{Binding Path=Quote.Ask}" Style="{StaticResource ResourceKey=BidStyle}"/>
        <Label x:Name="SpreadLabel" HorizontalAlignment="Left" Margin="102,99,0,0" VerticalAlignment="Top" Content="{Binding Path=Quote.BidAskSpread}" Style="{StaticResource ResourceKey=BidStyle}"/>
    </Grid>
</Window>

ViewModel

public class QuoteViewModel : ViewModelBase
{
    private readonly FakeDataGenerator _dataGenerator;
    private Quote _quote;
    private bool _bidHigher;
    private bool _bidLower;
    private bool _askHigher;
    private bool _askLower;
    private bool _spreadHigher;
    private bool _spreadLower;

    public QuoteViewModel()
    {
        _dataGenerator = new FakeDataGenerator();
        _dataGenerator.NewQuoteEvent += DataGeneratorOnNewQuoteEvent;
    }

    private void DataGeneratorOnNewQuoteEvent(Quote quote)
    {
        Quote = quote;
    }

    public Quote Quote
    {
        get { return _quote; }
        set 
        {
            if (_quote != value)
            {
                UpdateQuoteComparisons(_quote, value);
                _quote = value;
                OnPropertyChanged("Quote");
            }
        }
    }

    private void UpdateQuoteComparisons(Quote existingQuote, Quote newQuote)
    {
        if(existingQuote == null)
        {
            return;
        }

        if (newQuote.Bid > existingQuote.Bid)
        {
            BidHigher = true;
        }
        else if (newQuote.Bid < existingQuote.Bid)
        {
            BidLower = true;
        }

        if (newQuote.Ask > existingQuote.Ask)
        {
            AskHigher = true;
        }
        else if (newQuote.Ask < existingQuote.Ask)
        {
            AskLower = true;
        }

        if (newQuote.BidAskSpread > existingQuote.BidAskSpread)
        {
            SpreadHigher = true;
        }
        else if (newQuote.BidAskSpread < existingQuote.BidAskSpread)
        {
            SpreadLower = true;
        }
    }

    public bool BidHigher
    {
        get { return _bidHigher; }
        set
        {
            _bidHigher = value;
            OnPropertyChanged("BidHigher");
        }
    }

    public bool BidLower
    {
        get { return _bidLower; }
        set
        {
            _bidLower = value;
            OnPropertyChanged("BidLower");
        }
    }

    public bool AskHigher
    {
        get { return _askHigher; }
        set
        {
            _askHigher = value;
            OnPropertyChanged("AskHigher");
        }
    }

    public bool AskLower
    {
        get { return _askLower; }
        set
        {
            _askLower = value;
            OnPropertyChanged("AskLower");
        }
    }

    public bool SpreadHigher
    {
        get { return _spreadHigher; }
        set
        {
            _spreadHigher = value;
            OnPropertyChanged("SpreadHigher");
        }
    }

    public bool SpreadLower
    {
        get { return _spreadLower; }
        set
        {
            _spreadLower = value;
            OnPropertyChanged("SpreadLower");
        }
    }
}

Upvotes: 2

Views: 3444

Answers (1)

KornMuffin
KornMuffin

Reputation: 2957

You could try stopping the storyboard via the DataTrigger.ExitActions (you'll have to name you existing BeginStoryboard's):

        <DataTrigger Binding="{Binding Path=SpreadLower}" Value="True">
            <DataTrigger.EnterActions>
                <BeginStoryboard Name="SpreadLowerStoryboard>
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetProperty="Background.Color" To="Red" Duration="0:0:0.2" AutoReverse="True"/>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.EnterActions>
            <DataTrigger.ExitActions>
                <StopStoryboard BeginStoryboardName="SpreadLowerStoryboard" />
            </DataTrigger.ExitActions>
        </DataTrigger>

Upvotes: 2

Related Questions