Подскажите, пожалуйста, как решить проблему. Я делаю анимацию смены UserControl, решение нашел сдесь: Как анимировать смену одного контрола на другой?
Анимация работает, но когда меняется предыдущий UserControl при выборе нового, то он не анимируется, а просто исчезает и начинает работать анимация выбранного UserControl.
[TemplatePart(Name = "PART_Animation", Type = typeof(Storyboard))]
public class AnimatableContentPresenter : Control
{
static AnimatableContentPresenter()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(AnimatableContentPresenter),
new FrameworkPropertyMetadata(typeof(AnimatableContentPresenter)));
}
Storyboard animation; // текущая анимация
bool isAnimationRunning = false;
#region dp object Content, on change OnContentChanged
public object Content
{
get { return (object)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
public static readonly DependencyProperty ContentProperty =
DependencyProperty.Register(
"Content", typeof(object), typeof(AnimatableContentPresenter),
new PropertyMetadata(OnContentChangedStatic));
static void OnContentChangedStatic(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var self = (AnimatableContentPresenter)d;
self.OnContentChanged(e.OldValue, e.NewValue);
}
#endregion
#region dp object PreviousContent
public object PreviousContent
{
get { return (object)GetValue(PreviousContentProperty); }
set { SetValue(PreviousContentProperty, value); }
}
public static readonly DependencyProperty PreviousContentProperty =
DependencyProperty.Register(
"PreviousContent", typeof(object), typeof(AnimatableContentPresenter));
#endregion
// когда Content поменяется...
void OnContentChanged(object oldContent, object newContent)
{
if (isAnimationRunning)
animation?.Stop();
// ... запомним старый Content в PreviousContent
PreviousContent = oldContent;
// и перезапустим анимацию
if (animation != null)
{
animation.Begin();
isAnimationRunning = true;
}
}
// при появлении шаблона, вычитаем из него анимацию
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (animation != null)
animation.Completed -= OnAnimationCompleted;
if (isAnimationRunning)
{
// TODO: начать новую анимацию там, где предыдущая завершилась?
animation?.Stop();
}
animation = (Storyboard)Template.FindName("PART_Animation", this);
if (animation != null) // подпишемся на завершение анимации
animation.Completed += OnAnimationCompleted;
}
// по окончанию анимации...
private void OnAnimationCompleted(object sender, EventArgs e)
{
// выбросим старый контент
PreviousContent = null;
// сбросим эффект анимации
animation.Remove();
isAnimationRunning = false;
}
}
Стиль:
<Style TargetType="{x:Type local:AnimatableContentPresenter}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:AnimatableContentPresenter}">
<!-- несколько трюков с layout manager'ом, чтобы
избежать умножения через конвертер -->
<Grid Name="Root" ClipToBounds="True">
<Grid HorizontalAlignment="Left">
<!-- ширина вдвое больше Root -->
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="{Binding ActualWidth, ElementName=Root}"/>
<ColumnDefinition
Width="{Binding ActualWidth, ElementName=Root}"/>
</Grid.ColumnDefinitions>
<!-- растянем на всю ширину -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"
Grid.ColumnSpan="2">
<!-- старый контент -->
<ContentPresenter
Content="{TemplateBinding PreviousContent}"
Style="{x:Null}"
Width="{Binding ActualWidth, ElementName=Root}"/>
<!-- текущий контент -->
<ContentPresenter
Content="{TemplateBinding Content}"
Style="{x:Null}"
Width="{Binding ActualWidth, ElementName=Root}"/>
<!-- анимируемая распорка -->
<Grid Width="{Binding ActualWidth, ElementName=Root}"
Name="Strut">
<Grid.Resources>
<Storyboard x:Key="Animation" x:Name="PART_Animation">
<DoubleAnimation
Storyboard.TargetName="Strut"
Storyboard.TargetProperty="Width"
From="0"
Duration="0:0:0.4">
<DoubleAnimation.EasingFunction>
<ExponentialEase EasingMode="EaseInOut"
Exponent="1.2"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</Grid.Resources>
</Grid>
</StackPanel>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
ListBox:
<ListBox ItemsSource="{Binding ElementName=Control, Path=ItemsSource}"
SelectedItem="{Binding ElementName=Control,Path=SelectedItem}"
BorderThickness="0" Background="Transparent"
ItemContainerStyle="{StaticResource CustomListBoxItem}" Width="50"
ScrollViewer.VerticalScrollBarVisibility="Disabled"/>
<local:NavigationMenu ItemsSource="{Binding MenuItem, Mode=TwoWay}"
SelectedItem="{Binding SelectedMenu, Mode=TwoWay}"/>
ContentControl:
<ContentControl Content="{Binding CurrentContent, Mode=TwoWay, IsAsync=True}"
Style="{StaticResource LeftToRightAnimatedContentControl}"/>
Стиль ContentControl:
<Style TargetType="{x:Type ContentControl}" x:Key="LeftToRightAnimatedContentControl">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<local:AnimatableContentPresenter Content="{Binding}"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>