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.
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.