Fluid Move Behavior - List animation Silverlight


In this article we are going to learn about the List animation in Fluid UI.

Let's start up with a New Silverlight Project.

Let's add a few References.

Fluid1.gif

Fluid2.gif

Once we have added the References we can add the data for our List. This will be our DataModel.

Below is the code for the DataModel:

public class FoodModel : INotifyPropertyChanged
    {
        private List<FoodModelItem> masterList = new List<FoodModelItem>()
                     {
                           new FoodModelItem() { Name = "Chocolate Cake", IsLiked = true, Order = 10 },
                           new FoodModelItem() { Name = "Brussels Sprouts", IsLiked = false, Order = 11 },
                           new FoodModelItem() { Name = "Mocha Ice Cream", IsLiked = true, Order = 12 },
                           new FoodModelItem() { Name = "Asparagus", IsLiked = false, Order = 13 },
                           new FoodModelItem() { Name = "Sushi", IsLiked = true, Order = 14 },
                           new FoodModelItem() { Name = "Cilantro", IsLiked = false, Order = 15 },
                           new FoodModelItem() { Name = "Diet Coke", IsLiked = true, Order = 16 },
                           new FoodModelItem() { Name = "Tequila", IsLiked = false, Order = 17 },
                           new FoodModelItem() { Name = "Habanero Peppers", IsLiked = true, Order = 18 },
                           new FoodModelItem() { Name = "Lutefisk", IsLiked = false, Order = 19 },
                           new FoodModelItem() { Name = "Sauerkraut", IsLiked = true, Order = 20 },
                           new FoodModelItem() { Name = "Haggis", IsLiked = false, Order = 21 }
                     };

        private ObservableCollection<FoodModelItem> foodsILike = new ObservableCollection<FoodModelItem>();
        private ObservableCollection<FoodModelItem> foodsIHate = new ObservableCollection<FoodModelItem>();
        private double numberOfItems;

        public ObservableCollection<FoodModelItem> FoodsILike { get { return this.foodsILike; } }
        public ObservableCollection<FoodModelItem> FoodsIHate { get { return this.foodsIHate; } }
        public double MaxNumberOfItems { get { return this.masterList.Count; } }
        public double NumberOfItems
        {
            get { return this.numberOfItems; }
            set { this.numberOfItems = value; this.OnPropertyChanged("NumberOfItems"); this.UpdateCollections(); }
        }

        public FoodModel()
        {
            this.numberOfItems = this.masterList.Count;

            foreach (FoodModelItem item in this.masterList)
            {
                item.PropertyChanged += OnItemPropertyChanged;
            }

            this.UpdateCollections();
        }

        private void UpdateCollections()
        {
            this.UpdateObservableCollection(this.FoodsILike, true);
            this.UpdateObservableCollection(this.FoodsIHate, false);
        }

        private void UpdateObservableCollection(ObservableCollection<FoodModelItem> collection, bool filter)
        {
            int index = 0;
            int collectionIndex = 0;

            foreach (FoodModelItem item in this.masterList)
            {
                bool itemIsAvailable = collectionIndex < this.NumberOfItems;

                if (item.IsLiked == filter && itemIsAvailable)
                {
                    if (index >= collection.Count || collection[index] != item)
                    {
                        if (collection.Contains(item))
                        {
                            collection.Remove(item); // don't have it in place twice
                        }
                        collection.Insert(index, item);
                    }
                    index++;
                }
                else
                {
                    if (index < collection.Count && collection[index] == item)
                    {
                        collection.RemoveAt(index);
                    }
                }

                collectionIndex++;
            }

            while (collection.Count > index)
            {
                collection.RemoveAt(index);
            }
        }

        private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this.UpdateCollections();
        }

        public void SortOriginal()
        {
            this.masterList.Sort(new Comparison<FoodModelItem>(delegate(FoodModelItem a, FoodModelItem b) { return (int)(a.Order - b.Order); }));
            this.UpdateCollections();
        }

        public void SortAlphabetical()
        {
            this.masterList.Sort(new Comparison<FoodModelItem>(delegate(FoodModelItem a, FoodModelItem b) { return String.Compare(a.Name, b.Name); }));
            this.UpdateCollections();
        }

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

    public class FoodModelItem : INotifyPropertyChanged
    {
        private string name = string.Empty;
        public string Name
        {
            get { return this.name; }
            set { if (this.name != value) { this.name = value; this.OnPropertyChanged("Name"); } }
        }

        private bool isLiked = false;
        public bool IsLiked
        {
            get { return this.isLiked; }
            set { if (this.isLiked != value) { this.isLiked = value; this.OnPropertyChanged("IsLiked"); } }
        }

        private double order = 0;
        public double Order
        {
            get { return this.order; }
            set { if (this.order != value) { this.order = value; this.OnPropertyChanged("Order"); } }
        }

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


The XAML code is given below:

<UserControl x:Class="ListAnimation.MainPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
       xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
       xmlns:il="clr-namespace:Microsoft.Expression.Interactivity.Layout;assembly=Microsoft.Expression.Interactions"
       xmlns:System="clr-namespace:System;assembly=mscorlib"
       xmlns:ic="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
       xmlns:ee="http://schemas.microsoft.com/expression/2010/effects"
       xmlns:local="clr-namespace:ListAnimation"
       mc:Ignorable="d"

    d:DesignHeight="300" d:DesignWidth="400">

    <UserControl.Resources>
        <local:FoodModel x:Key="FoodModelDataSource" d:IsDataSource="True"/>

        <DataTemplate x:Key="ItemTemplateLike">
            <Grid Background="#01424242">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseLeftButtonDown">
                        <ic:ChangePropertyAction TargetObject="{Binding Mode=OneWay}" PropertyName="IsLiked" Value="False"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
                <TextBlock Margin="5,0,0,0" Text="{Binding Name}" FontSize="24" Foreground="#FFF0F0F0"/>
            </Grid>
        </DataTemplate>

        <DataTemplate x:Key="ItemTemplateDislike">
            <Grid Background="#01424242">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseLeftButtonDown">
                        <ic:ChangePropertyAction TargetObject="{Binding Mode=OneWay}" PropertyName="IsLiked" Value="True"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
                <TextBlock Margin="5,0,0,0" Text="{Binding Name}" FontSize="24" Foreground="#FFF0F0F0"/>
            </Grid>
        </DataTemplate>

        <ItemsPanelTemplate x:Key="ItemsPanelTemplate1">
            <StackPanel>
                <i:Interaction.Behaviors>
                    <il:FluidMoveBehavior AppliesTo="Children" Duration="0:0:1" Tag="DataContext">
                        <il:FluidMoveBehavior.EaseY>
                            <BackEase EasingMode="EaseInOut" Amplitude="0.5"/>
                        </il:FluidMoveBehavior.EaseY>
                        <il:FluidMoveBehavior.EaseX>
                            <BackEase EasingMode="EaseInOut" Amplitude="0.5"/>
                        </il:FluidMoveBehavior.EaseX>
                    </il:FluidMoveBehavior>
                </i:Interaction.Behaviors>
            </StackPanel>
        </ItemsPanelTemplate>
        <Style x:Key="ListBoxItemStyle1" TargetType="ListBoxItem">
            <Setter Property="Padding" Value="3"/>
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="VerticalContentAlignment" Value="Top"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="TabNavigation" Value="Local"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                        <Grid x:Name="grid" Background="{TemplateBinding Background}">
                            <VisualStateManager.CustomVisualStateManager>
                                <ic:ExtendedVisualStateManager/>
                            </VisualStateManager.CustomVisualStateManager>
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="LayoutStates">
                                    <VisualStateGroup.Transitions>
                                        <VisualTransition GeneratedDuration="0:0:0.5">
                                            <ic:ExtendedVisualStateManager.TransitionEffect>
                                                <ee:PixelateTransitionEffect/>
                                            </ic:ExtendedVisualStateManager.TransitionEffect>
                                        </VisualTransition>
                                    </VisualStateGroup.Transitions>
                                    <VisualState x:Name="BeforeLoaded">
                                        <Storyboard>
                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="grid">
                                                <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
                                            </DoubleAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="AfterLoaded"/>
                                    <VisualState x:Name="BeforeUnloaded">
                                        <Storyboard>
                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="grid">
                                                <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
                                            </DoubleAnimationUsingKeyFrames>|
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <DataTemplate x:Key="FoodModelItemTemplate">
            <StackPanel>
                <CheckBox IsChecked="{Binding IsLiked, Mode=TwoWay}"/>
                <TextBlock Text="{Binding Name}"/>
                <TextBlock Text="{Binding Order}"/>
            </StackPanel>
        </DataTemplate>
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" DataContext="{StaticResource FoodModelDataSource}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.5*"/>
            <ColumnDefinition Width="0.5*"/>
        </Grid.ColumnDefinitions>
        <TextBlock Margin="20,8,0,0" VerticalAlignment="Top" FontFamily="Segoe UI" FontSize="32" Foreground="#FFF0F0F0" HorizontalAlignment="Left" d:LayoutOverrides="GridBox" Text="V4 FluidMoveBehavior (cont.)" Grid.ColumnSpan="2"/>
        <ListBox x:Name="FoodsILikeListBox" Margin="40,80,20,60" ItemsSource="{Binding FoodsILike}" ItemTemplate="{StaticResource ItemTemplateLike}" Foreground="#FFCACACA" Background="#FF333333" FontSize="16" ItemsPanel="{StaticResource ItemsPanelTemplate1}" ItemContainerStyle="{StaticResource ListBoxItemStyle1}" BorderBrush="{x:Null}"/>
        <ListBox x:Name="FoodsIHateListBox" Margin="20,80,40,60" Grid.Column="1" ItemsSource="{Binding FoodsIHate}" ItemTemplate="{StaticResource ItemTemplateDislike}" Foreground="#FFCACACA" Background="#FF333333" FontSize="16" ItemsPanel="{StaticResource ItemsPanelTemplate1}" ItemContainerStyle="{StaticResource ListBoxItemStyle1}" BorderBrush="{x:Null}"/>
        <Slider x:Name="NumberOfItems" Margin="20,0,40,24" VerticalAlignment="Bottom" Maximum="{Binding MaxNumberOfItems}" SmallChange="1" Value="{Binding NumberOfItems, Mode=TwoWay}" Grid.Column="1"/>
        <CheckBox Content="Alphabetical" Height="18" Margin="40,0,20,24" VerticalAlignment="Bottom" Foreground="#FFCACACA">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Checked">
                    <ic:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="SortAlphabetical"/>
                </i:EventTrigger>
                <i:EventTrigger EventName="Unchecked">
                    <ic:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="SortOriginal"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </CheckBox>
    </Grid>
</
UserControl>

We are done. Let's run the application.

As can be seen in the diagram, when we click on the item, the item moves from one List to another and we can see its path as well.

Fluid3.gif

 

Up Next
    Ebook Download
    View all
    Learn
    View all