UWP Loop Fade Animation

384 Views Asked by At

I have a Pivot and its header template is a user control and I want to start a continuous Flashing ( Fade Out Fade In ) animation on it on a specific trigger and then also want to stop it on a specific trigger, while both of these triggers/events will happen in the ViewModel of the page. I can take care of the triggers but my only issue is I am not sure how to achieve the infinite flashing behavior. The header has to start flashing when I tell it to and has to keep flashing until I tell it to stop. I wonder if there is some sort of Repeat animation property in xaml but couldn't find that in xaml animations from Community Toolkit

Queue is the model class which defines the context of HeaderTemplate, so I've custom events to start and stop the flashing, because I have access to that Queue object instance within the ViewModel of my page.

All the custom logic happens in code behind of the User Control. Attached is the code I have tried below. I would prefer if this is somehow done all in xaml or mostly in xaml so I can avoid any infinite loops or memory leak risks. My current attempt just freezes the UI and rightly so as I am doing an infinite loop which makes stuff just weird.

Code

Pivot Header

<Pivot.HeaderTemplate>
            <DataTemplate x:DataType="cad:Queue">
                <dataTemplates:HomePivotHeaderTemplate />
            </DataTemplate>
</Pivot.HeaderTemplate>

Queue class

public partial class Queue
{
    public event EventHandler<EventArgs> StartFlash;
    public event EventHandler<EventArgs> StopFlash;

    public void OnStartFlash() => StartFlash?.Invoke(this, EventArgs.Empty);
    public void OnStopFlash() => StopFlash?.Invoke(this, EventArgs.Empty);
}

Triggers in ViewModel

    public void StartFlashingPendingQueues()
    {
         PivotQueues.First()?.OnStartFlash();            
    }

    private void StopFlashingPendingQueues()
    {
         PivotQueues.First()?.OnStopFlash();
    }

UserControl for Data Template

 public sealed partial class HomePivotHeaderTemplate : UserControl
{
    public Queue VM => DataContext as Queue;
    private bool _IsFlashing;
    private bool _unLoaded;
    public HomePivotHeaderTemplate()
    {
        InitializeComponent();
        Loaded += HomePivotHeaderTemplate_Loaded;
        Unloaded += HomePivotHeaderTemplate_Unloaded;
        DataContextChanged += (s, e) => Bindings.Update();
    }

    private void HomePivotHeaderTemplate_Unloaded(object sender, RoutedEventArgs e)
    {
        _unLoaded = true;
        Loaded -= HomePivotHeaderTemplate_Loaded;
        Unloaded -= HomePivotHeaderTemplate_Unloaded;
        VM.StartFlash -= VM_StartFlash;
        VM.StopFlash -= VM_StopFlash;
    }

    private void HomePivotHeaderTemplate_Loaded(object sender, RoutedEventArgs e)
    {
        VM.StartFlash += VM_StartFlash;
        VM.StopFlash += VM_StopFlash;
        VM_Flashed();
    }

    private void VM_StopFlash(object sender, System.EventArgs e) => _IsFlashing = false;

    private void VM_StartFlash(object sender, System.EventArgs e) => _IsFlashing = true;

    private async Task VM_Flashed()
    {
        while (true)
        {
            if (_unLoaded)
            {
                break;
            }
            else
            {
                if (_IsFlashing)
                {
                    await Block.Fade(value: 0f, duration: 500, delay: 0, easingType: EasingType.Linear, easingMode: EasingMode.EaseOut).Then().Fade(value: 1f, duration: 500, delay: 0, easingType: EasingType.Linear, easingMode: EasingMode.EaseIn).StartAsync();
                }
            }
        }
    }
}

Edit 1

If I can somehow figure out how to give infinite flashing animation to the textblock I can take care of the rest. basically I could just have 2 textblocks identical, one of them will be flashing other won't, and I can toggle their visibility based on triggers in my viewmodel.

1

There are 1 best solutions below

0
On

I guess I was just overthinking it. It was a simple DoubleAnimation in a StoryBoard

UserControl code behind

public sealed partial class HomePivotHeaderTemplate : UserControl
{
    public Queue VM => DataContext as Queue;
    public HomePivotHeaderTemplate()
    {
        InitializeComponent();
        Loaded += HomePivotHeaderTemplate_Loaded;
        Unloaded += HomePivotHeaderTemplate_Unloaded;
        DataContextChanged += (s, e) => Bindings.Update();
    }

    private void HomePivotHeaderTemplate_Unloaded(object sender, RoutedEventArgs e)
    {
        Loaded -= HomePivotHeaderTemplate_Loaded;
        Unloaded -= HomePivotHeaderTemplate_Unloaded;
        VM.StartFlash -= VM_StartFlash;
        VM.StopFlash -= VM_StopFlash;
    }

    private void HomePivotHeaderTemplate_Loaded(object sender, RoutedEventArgs e)
    {
        VM.StartFlash += VM_StartFlash;
        VM.StopFlash += VM_StopFlash;
    }

    private void VM_StopFlash(object sender, System.EventArgs e) => FlashStoryBoard.Stop();

    private void VM_StartFlash(object sender, System.EventArgs e) => FlashStoryBoard.Begin();
}

UserControl Xaml

<UserControl.Resources>
    <Storyboard x:Name="FlashStoryBoard">
        <DoubleAnimation Storyboard.TargetName="Block" Storyboard.TargetProperty="Opacity"
            Duration="0:0:2"
            From="1"
            RepeatBehavior="Forever"
            To="0.2" />
    </Storyboard>
</UserControl.Resources>
<TextBlock x:Name="Block"
    Text="{x:Bind VM.Name}" />