3
votes

In a WPF project, I have an ItemsControl bound to a collection of the ViewModel. It's ItemTemplate contains an Image control bound to property of the object collection. I have a timer which fetches new images every minute from a JSON service and assigns them to that property bound to the Image.

What I wanna do is trigger a simple animation when that property changes. Particularly, I want to trigger a simple fade-out animation right before the new image is assigned to my property, that would involve the PropertyChanging event, and a fade-in animation on PropertyChanged so I would have a smooth transition from the old to new image in my View.

I've tried the following taken from another question but that triggers the animation after the property changes which isn't what I want:

<Image 
    x:Name="ChannelImage"
    Width="230" Height="230" 
    Source="{Binding ImageByteArray, Converter={StaticResource ByteArrayToBitmapImageConverter}, 
                                     NotifyOnTargetUpdated=True}">
    <Image.Triggers>
        <EventTrigger RoutedEvent="Binding.TargetUpdated">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation 
                        Storyboard.TargetName="ChannelImage"
                        Storyboard.TargetProperty="Opacity"
                        BeginTime="0:0:0"
                        Duration="0:0:1"
                        To="0"/>
                    <DoubleAnimation 
                        Storyboard.TargetName="ChannelImage"
                        Storyboard.TargetProperty="Opacity"
                        BeginTime="0:0:2"
                        Duration="0:0:1"
                        To="1"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Image.Triggers>
</Image>

Any help would be much appreciated.

1

1 Answers

4
votes

It is not that easy to fade out the old image and fade in a new one. In your situation, I would do the following to maintain a good separation of concerns:

  1. Fetch the image from the uri and create a new Image in code. If you need further info on that, have a look at this question on Stack Overflow.
  2. If you want to apply MVVM, you should perform step 1 in a view model and set the corresponding property that raises PropertyChanged. Otherwise just update the corresponding control that I mention in step 3 manually.
  3. Implement a custom ContentControl that actually does the heavy lifting: when its Content property changes, it fades out the old content and fades in the new one. This is the hardest part, but if you introduce this new control, you can write your view models the same way as before and leave all the fading stuff to this new control.

I've implemented a small project for you that you can download via this Dropbox link (requires .NET 4.5). I created the class AnimatedContentControl which is a WPF Custom Control that has two Content Presenters inside its default Control Template. When the Content property is set on this control, the old content gets assigned to the OldContent Dependency Property which is faded out. Afterwards, the new content is then faded in. All this is done using the storyboard FadeInFromRight that is part of the control templates' resources. This storyboard is started in the overriden method OnContentChanged in AnimatedContentControl.cs.

The other classes are just the MainWindow and the MainWindowViewModel which use the default MVVM pattern.

If you have any questions, please feel free to ask. I hope I could help you with this problem.