Trigger Animation while ViewModel boolean is True (half-implemented)

MatteoPiccioniMatteoPiccioni USMember ✭✭

Hello,
I have a listview with a number of Cells.
While a boolean in the viewmodel cells is true, an animations should play.
The animation should stops when the boolean became false.
I was able to trigger animation when boolean became true but it stops as the animation end.
How should I make animation live until/while the boolean is true?

This is TriggerAction AnimationTrigger.cs
using System;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace MyApp.Behaviors
{
    public class AnimationTrigger : TriggerAction<Image>
    {

        protected override async void Invoke(Image sender)
        {
            if (sender != null)
            {
                await PerformAnimation(sender);
            }
        }
        private async Task PerformAnimation(Image myElement)
        {
            uint timeout = 100;

            await myElement.TranslateTo(-6, 0, timeout);

            await myElement.TranslateTo(6, 0, timeout);

            await myElement.TranslateTo(-4, 0, timeout);

            await myElement.TranslateTo(4, 0, timeout);

            await myElement.TranslateTo(-2, 0, timeout);

            await myElement.TranslateTo(2, 0, timeout);

            myElement.TranslationX = 0;
        }
    }
}

In my Cell definition a have a Image to animate

...
            <Image Grid.Row="0"
                   x:Name="btConnessione"
                   Grid.Column="2"
                   Margin="0,0,5,0"
                   WidthRequest="30"
                   HeightRequest="30"
                   HorizontalOptions="EndAndExpand"
                   VerticalOptions="Center">
                <Image.Source>
                    <FontImageSource FontFamily="{DynamicResource MaterialFontFamily}"
                                     Glyph="{Binding TipoConnessioneFont}"
                                     Size="44"
                                     Color="{Binding IconColorFont}" />
                </Image.Source>

                <Label.GestureRecognizers>
                    <TapGestureRecognizer Command="{Binding ParentContext.MyCommand, Source={x:Reference myCell}}" CommandParameter="{Binding .}" />
                </Label.GestureRecognizers>

                <Image.Triggers>
                    <DataTrigger TargetType="Image" Binding="{Binding IsRefreshing}" Value="True">
                        <DataTrigger.EnterActions>
                            <behaviors:AnimationTrigger />  
                        </DataTrigger.EnterActions>                                
                    </DataTrigger>
                </Image.Triggers>

            </Image>
...

AnimationTrigger starts where IsRefreshing became true...how could I have it playing until IsRefreshing is true?

Thanks

Best Answers

  • MatteoPiccioniMatteoPiccioni US ✭✭
    Accepted Answer

    Thanks, it should works now

    I did in this way, maybe can be useful for others

        public class AnimationTrigger : TriggerAction<Image>
        {
            public AnimationAction Action { get; set; }
            public enum AnimationAction
            { Start, Stop }
    
            protected override async void Invoke(Image sender)
            {
                if (sender != null)
                {
                    if (Action == AnimationAction.Start)
                        await PerformAnimation(sender);
                    else if (Action == AnimationAction.Stop)
                        CancelAnimation(sender);
                }
            }
    
            private async Task PerformAnimation(Image myElement)
            {
                uint timeout = 100;
    
                await myElement.TranslateTo(-6, 0, timeout);
    
                await myElement.TranslateTo(6, 0, timeout);
    
                await myElement.TranslateTo(-4, 0, timeout);
    
                await myElement.TranslateTo(4, 0, timeout);
    
                await myElement.TranslateTo(-2, 0, timeout);
    
                await myElement.TranslateTo(2, 0, timeout);
    
                myElement.TranslationX = 0;
    
                /*
                new Animation {
        { 0, 0.5, new Animation (v => myElement.Scale = v, 1, 2) },
        { 0, 1, new Animation (v => myElement.Rotation = v, 0, 360) },
        { 0.5, 1, new Animation (v => myElement.Scale = v, 2, 1) }
        }.Commit(myElement, "ChildAnimations", 16, 4000, null, null, () => true);
                */
    
    
            }
    
            private void CancelAnimation(Image myElement)
            {
               ViewExtensions.CancelAnimations(myElement);
    //           myElement.AbortAnimation("ChildAnimations");
    
            }
        }
    

    And my cell:

    ...
                <Image Grid.Row="0"
                       x:Name="btConnessione"
                       Grid.Column="2"
                       Margin="0,0,5,0"
                       WidthRequest="30"
                       HeightRequest="30"
                       HorizontalOptions="EndAndExpand"
                       VerticalOptions="Center">
                    <Image.Source>
                        <FontImageSource FontFamily="{DynamicResource MaterialFontFamily}"
                                         Glyph="{Binding TipoConnessioneFont}"
                                         Size="44"
                                         Color="{Binding IconColorFont}" />
                    </Image.Source>
    
                    <Label.GestureRecognizers>
                        <TapGestureRecognizer Command="{Binding ParentContext.MyCommand, Source={x:Reference myCell}}" CommandParameter="{Binding .}" />
                    </Label.GestureRecognizers>
    
                    <Image.Triggers>
                        <DataTrigger TargetType="Image"  Binding="{Binding IsRefreshing}" Value="True">
                            <DataTrigger.EnterActions>
                                <behaviors:AnimationTrigger Action="Start" />  
                            </DataTrigger.EnterActions>                                
                        </DataTrigger>
                        <DataTrigger TargetType="Image" Binding="{Binding IsRefreshing}" Value="False">
                            <DataTrigger.EnterActions>
                                <behaviors:AnimationTrigger  Action="Stop" />  
                            </DataTrigger.EnterActions>                                
                        </DataTrigger>                    
                    </Image.Triggers>
    
                </Image>
    ...
    

Answers

  • LeonLuLeonLu Member, Xamarin Team Xamurai

    Based on my research, You cannot bind the IsRefreshing of listview to DataTrigger directly, you should enable the pull to refresh IsPullToRefreshEnabled="true" in listview and add the property(reflesh) of model, binding it to DataTrigger, If the listview was pulled, AnimationTrigger starts

  • MatteoPiccioniMatteoPiccioni USMember ✭✭

    Thanks for answer

    The IsRefreshing property is not linked to the listview viewmodel
    The listview in a different viewmodel.

    Each cells have a own viewmodel, with a thread for self-update in background...the IsRefreshing property is in each cell's viewmodel.
    In the cell viewmodel, when the thread starts the 'update command', it sets the property IsRefreshing to true.
    The DataTrigger works well, and animation starts. When the command ends, the IsRefreshing property is set to false.

    Id like to have the animation running until the property IsRefreshing value is true.

  • LeonLuLeonLu Member, Xamarin Team Xamurai

    Your implementation is correct, do you want to update the value of IsRefreshing dynamically? If not, please provide more information to me.

  • MatteoPiccioniMatteoPiccioni USMember ✭✭

    I already update IsRefreshing on cell viewmodel.

    I want to stop animation when the value of IsRefreshing become false.
    In my implementation the animation starts when IsRefreshing become true, but ends after a fixed time
    uint timeout = 100;

    I want to decide when stop the animation manually from viewmodel using IsRefreshing property
    Thanks

  • MatteoPiccioniMatteoPiccioni USMember ✭✭
    Accepted Answer

    Thanks, it should works now

    I did in this way, maybe can be useful for others

        public class AnimationTrigger : TriggerAction<Image>
        {
            public AnimationAction Action { get; set; }
            public enum AnimationAction
            { Start, Stop }
    
            protected override async void Invoke(Image sender)
            {
                if (sender != null)
                {
                    if (Action == AnimationAction.Start)
                        await PerformAnimation(sender);
                    else if (Action == AnimationAction.Stop)
                        CancelAnimation(sender);
                }
            }
    
            private async Task PerformAnimation(Image myElement)
            {
                uint timeout = 100;
    
                await myElement.TranslateTo(-6, 0, timeout);
    
                await myElement.TranslateTo(6, 0, timeout);
    
                await myElement.TranslateTo(-4, 0, timeout);
    
                await myElement.TranslateTo(4, 0, timeout);
    
                await myElement.TranslateTo(-2, 0, timeout);
    
                await myElement.TranslateTo(2, 0, timeout);
    
                myElement.TranslationX = 0;
    
                /*
                new Animation {
        { 0, 0.5, new Animation (v => myElement.Scale = v, 1, 2) },
        { 0, 1, new Animation (v => myElement.Rotation = v, 0, 360) },
        { 0.5, 1, new Animation (v => myElement.Scale = v, 2, 1) }
        }.Commit(myElement, "ChildAnimations", 16, 4000, null, null, () => true);
                */
    
    
            }
    
            private void CancelAnimation(Image myElement)
            {
               ViewExtensions.CancelAnimations(myElement);
    //           myElement.AbortAnimation("ChildAnimations");
    
            }
        }
    

    And my cell:

    ...
                <Image Grid.Row="0"
                       x:Name="btConnessione"
                       Grid.Column="2"
                       Margin="0,0,5,0"
                       WidthRequest="30"
                       HeightRequest="30"
                       HorizontalOptions="EndAndExpand"
                       VerticalOptions="Center">
                    <Image.Source>
                        <FontImageSource FontFamily="{DynamicResource MaterialFontFamily}"
                                         Glyph="{Binding TipoConnessioneFont}"
                                         Size="44"
                                         Color="{Binding IconColorFont}" />
                    </Image.Source>
    
                    <Label.GestureRecognizers>
                        <TapGestureRecognizer Command="{Binding ParentContext.MyCommand, Source={x:Reference myCell}}" CommandParameter="{Binding .}" />
                    </Label.GestureRecognizers>
    
                    <Image.Triggers>
                        <DataTrigger TargetType="Image"  Binding="{Binding IsRefreshing}" Value="True">
                            <DataTrigger.EnterActions>
                                <behaviors:AnimationTrigger Action="Start" />  
                            </DataTrigger.EnterActions>                                
                        </DataTrigger>
                        <DataTrigger TargetType="Image" Binding="{Binding IsRefreshing}" Value="False">
                            <DataTrigger.EnterActions>
                                <behaviors:AnimationTrigger  Action="Stop" />  
                            </DataTrigger.EnterActions>                                
                        </DataTrigger>                    
                    </Image.Triggers>
    
                </Image>
    ...
    
  • LeonLuLeonLu Member, Xamarin Team Xamurai

    Thanks for your sharing. Happy coding.

Sign In or Register to comment.