04. February 2020
UI animation from your ViewModel
This post is all about accessing your views code-behind from your viewModel and nothing much about animation sorry!
I’m writing this because I needed to kick off an animation in my View page code-behind and I found that the usually preferred way (using Prisms PropertyChanged) didn’t work that great for me.
What was I trying to do?
I’m still working with buttons like my previous blog post Circle button in Xamarin.Forms but now I’m doing custom animation like this image shows.
Two ways to do this
There are at least two ways to talk between the view and view-model so here goes.
Method 1: Using PropertyChanged
Lets first take a look at how you can do this with PropertyChanged
The ViewModel
Add a property to your model that you want to subscribe to changes to in the View page.
private bool? _isCorrectAnswer;
public bool? IsCorrectAnswer
{
get { return _isCorrectAnswer; }
set { SetProperty(ref _isCorrectAnswer, value); }
}
Then change the value to the property somewhere in your code to
IsCorrectAnswer = true;
The View
Then setup your view like this
public partial class AnimationPage : ContentPage
{
public AnimationPageViewModel? ViewModel
=> BindingContext as AnimationPageViewModel;
public AnimationPage()
{
InitializeComponent();
if (ViewModel != null)
{
ViewModel.PropertyChanged += VM_PropertyChanged;
}
}
/// <summary>
/// Called when there is a change to any property on the viewModel
/// </summary>
private void VM_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
// Did the property we are interested in change?
if (e.PropertyName == "IsCorrectAnswer")
{
// Do some UI animation code
DoAnimationMethod(((MultiplyPageViewModel)sender)?.IsCorrectAnswer);
}
}
}
And now the DoAnimationMethod() is always called when the IsCorrectAnswer in the view model changes.
But why didn’t that work for me?
Because I need I basically need to reset this property for my logic to work. So either setting it back to default false or even changing it to a nullable string (string?) will trigger the PropertyChanged.
Maybe I could have changed my logic to make this work but I decided there was a better way in this instance to do this.
Method 2: Using a EventHandler
Here I’m going to use EventHandlers like I talked about in my blog post Events and this is the approach I ended on taking.
The ViewModel
Add this code to your ViewModel
public event EventHandler<ChangeColorsArgs> ChangeButtonColorsEvent;
private void ChangeButtonColors(bool isCorrectAnswer)
{
ChangeButtonColorsEvent?.Invoke(this, new ColorsArgs(isCorrectAnswer));
}
and call the method ChangeButtonColors() from your code
ChangeButtonColors(true);
EventArg
You need to create your own eventArgs to pass your parameters between so we do it like this
public class ChangeColorsArgs : System.EventArgs
{
public bool IsCorrectAnswer { get; set; }
public ChangeColorsArgs(bool correctAnswer)
{
IsCorrectAnswer = correctAnswer;
}
}
For more parameters just add them in there and to the constructor.
The View
Add this code to your view.
public partial class ButtonAnimationPage : ContentPage
{
public AnimationPageViewModel? ViewModel
=> BindingContext as AnimationPageViewModel;
public AnimationPage()
{
InitializeComponent();
if (ViewModel != null)
{
ViewModel.ChangeButtonColorsEvent += OnAnswerProvidedEvent;
}
}
/// <summary>
/// Called when event in viewModel is Invoked
/// </summary>
private async void OnAnswerProvidedEvent(object sender, ChangeColorsArgs e)
{
await DoAnimationMethod(e.IsCorrectAnswer);
}
}
And now the DoAnimationMethod() in your view gets called every time you call ChangeButtonColors(true) in your ViewModel.
##Easy?
Please hit me up on Twitter if I’m missing something and I’ll try to augment it.