Hi,
You can animate property and bind this property to many Controls and all showed animations will be synchonously.
XAML MainWindow:
<Window x:Class="WpfApp1.Window004"
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:local="clr-namespace:WpfApp004"
mc:Ignorable="d"
Title="Window004" Height="450" Width="800">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<StackPanel>
<Button Content="Add UserControl" Command="{Binding Cmd}" CommandParameter="AddUserControl" Margin="5" Width="200"/>
<ItemsControl ItemsSource="{Binding UserControls}"/>
</StackPanel>
</Window>
Classes:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using WpfControlLibrary1;
namespace WpfApp004
{
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
Animating = new AnimatedProperties();
Animating.AnimationCompleted += (sender, e) => OnPropertyChanged(nameof(Cmd));
}
public ObservableCollection<UserControl> UserControls { get; } = new ObservableCollection<UserControl>();
public AnimatedProperties Animating { get; }
public ICommand Cmd { get => new RelayCommand(CmdExec, CanCmdExec); }
private void CmdExec(Object parameter)
{
switch (parameter.ToString())
{
case "StartAnimation":
Animating.StartAnimation();
break;
case "AddUserControl":
UserControls.Add(new Window004UC1());
break;
default:
break;
}
}
private bool CanCmdExec(object obj) => Animating.ca == null;
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
public class AnimatedProperties : DependencyObject
{
public AnimatedProperties() => sb.Completed += (sender, e) => { ca = null; AnimationCompleted?.Invoke(this, new EventArgs()); };
public static readonly DependencyProperty AnimatedColorProperty =
DependencyProperty.RegisterAttached("AnimatedColor",
typeof(Color), typeof(AnimatedProperties), new UIPropertyMetadata(Colors.Red));
public static Color GetAnimatedColor(DependencyObject d) => (Color)(d.GetValue(AnimatedColorProperty));
public static void SetAnimatedColor(DependencyObject d, Color value) => d.SetValue(AnimatedColorProperty, value);
public ColorAnimation ca;
private Storyboard sb = new Storyboard();
public event EventHandler AnimationCompleted;
public void StartAnimation()
{
if (ca == null)
{
ca = new ColorAnimation()
{
From = Colors.Yellow,
To = Colors.Blue,
Duration = new Duration(TimeSpan.FromSeconds(2.0)),
RepeatBehavior = new RepeatBehavior(1),
AutoReverse = true
};
sb.Children.Clear();
sb.Children.Add(ca);
Storyboard.SetTarget(ca, this);
Storyboard.SetTargetProperty(ca, new PropertyPath(AnimatedProperties.AnimatedColorProperty));
sb.Begin();
}
}
}
public class RelayCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _action;
public RelayCommand(Action<object> action) { _action = action; _canExecute = null; }
public RelayCommand(Action<object> action, Predicate<object> canExecute) { _action = action; _canExecute = canExecute; }
public void Execute(object o) => _action(o);
public bool CanExecute(object o) => _canExecute == null ? true : _canExecute(o);
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
}
XAML UserControl:
<UserControl x:Class="WpfControlLibrary1.Window004UC1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfControlLibrary004"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<local:ColorConverter x:Key="conv"/>
</UserControl.Resources>
<StackPanel>
<Button Content="Start Animation" Command="{Binding Cmd}" CommandParameter="StartAnimation" Margin="5" Width="100"/>
<Rectangle Fill="{Binding Animating.AnimatedColor, Converter={StaticResource conv}}" Height="50" Width="200" Margin="10"/>
</StackPanel>
</UserControl>
Converter Color to Brush:
public class ColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => new SolidColorBrush((Color)value);
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}
Result: