How could I animate one stack panel item at a time?

Let's say I have a StackPanel with multiple items in it. When I load my view, I want to apply some animation to them. But I want each element to animate sequentially, one by one. How should I do it? In particular, is there a clean way to do this within MVVM framework?

Edit. I should mention that items are bound to the StackPanel using the ItemsControl, which can complicate things a lot. Looks like this

                   <ItemsControl x:Name="Items">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel />
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <Button Content="{Binding ButtonName}"/>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>

      

Some of the user interface codes have been omitted for clarity.

+2


source to share


1 answer


Copy / Paste / Compile / Execute: I would throw up an explanation, but too many topics to cover. Basically the sample shows how to MultiTrigger, Animate, load elements in the background without freezing the UI, and using PropertyChanged to notify the UI. Enjoy.

Here's the XAML

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="350" Width="525"
    x:Name="wnd">
<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BoolToVisibility" />
</Window.Resources>

<ItemsControl x:Name="Items" ItemsSource="{Binding TestItems, ElementName=wnd}" Loaded="Items_Loaded">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button x:Name="item" Content="{Binding DisplayString}" Margin="5">
                <Button.Style>
                    <Style TargetType="{x:Type Button}">
                        <Setter Property="Opacity" Value="0"/>
                        <Setter Property="Visibility" Value="{Binding Path=IsVisible, Converter={StaticResource BoolToVisibility}}"/>
                        <Style.Triggers>
                            <MultiDataTrigger>
                                <MultiDataTrigger.Conditions>
                                    <Condition Binding="{Binding IsLoading}" Value="True"/>
                                    <Condition Binding="{Binding IsVisible}" Value="True"/>
                                </MultiDataTrigger.Conditions>
                                <MultiDataTrigger.EnterActions>
                                    <BeginStoryboard>
                                        <Storyboard >
                                            <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:1.5" AccelerationRatio="0.3"/>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </MultiDataTrigger.EnterActions>
                            </MultiDataTrigger>
                        </Style.Triggers>
                    </Style>
                </Button.Style>
            </Button>                   
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

      



Then here is the code for it:

using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace WpfApplication1
{

public partial class MainWindow : Window
{
    private List<TestItem> _items;
    public List<TestItem> TestItems
    {
        get
        {
            if(_items == null)
            {
                _items = new List<TestItem>();
                for(int i = 0; i < 10; i++)
                    _items.Add(new TestItem{ DisplayString = i.ToString(CultureInfo.InvariantCulture), IsVisible = true});
            }
                return _items;
        }
    }

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Items_Loaded(object sender, RoutedEventArgs e)
    {
        /*in background so not to freeze the UI thread*/
        Task.Factory
            .StartNew(() =>
                        {
                            foreach (var item in TestItems)
                            {
                                item.IsLoading = true;
                                item.IsVisible = true;
                                /*using sleep as quick and dirty just to slow down loading and show the animation (otherwise it a no-no )*/
                                Thread.Sleep(500);
                            }
                        }
            );
    }
}

public class TestItem : INotifyPropertyChanged
{
    private string _displayString;
    private bool _isVisible;
    private bool _isLoading;

    public string DisplayString
    {
        get { return _displayString; } 
        set
        {
            if (_displayString == value) return;
            _displayString = value;
            RaisePropertyChanged("DisplayString");
        }
    }

    public bool IsVisible
    {
        get { return _isVisible; }
        set
        {
            if (_isVisible == value) return;
            _isVisible = value;
            RaisePropertyChanged("IsVisible");
        }
    }

    public bool IsLoading
    {
        get { return _isLoading; }
        set
        {
            if (_isLoading == value) return;
            _isLoading = value;
            RaisePropertyChanged("IsLoading");
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        if(PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
}

      

+1


source







All Articles