Xamarin TextChanged Event on Two Fields That Change Each Other

In the new version of the Cashflow Calculator I am making with Xamarin, I wanted to create the ability to input most of the expenses as both exact money values if you knew them or percentages of the monthly rent. This is a very common method of estimating repairs, vacancies, and property management fees.

I Change You, You Change Me

The idea was to have the percentage get set whenever the cash value was changed and the cash value get set whenever the percentage was changed.

But if you just create a normal TextChanged event on both of them, as soon as you make a change to one, it fires its TextChanged event which changes the other field and fires the other field’s TextChanged event which sets the one you are working on.

This does not work.

Stop Listening For a Sec

The solution to this is to disconnect the field you are about to change from its TextChanged listener and reconnect it when you are done changing it. We will use the event for calculating our rent percentage from the price of the property as an example.


async void CalculateRentCash(object sender, TextChangedEventArgs e)
{
    monthly_rent_cash.TextChanged -= CalculateRentPercent;
    await Task.Yield();
    var percent_val = GetFloat(monthly_rent_percent.Text);
    var new_rent_cash = GetFloat(property_value.Text) * (percent_val/100.0);
    monthly_rent_cash.Text = new_rent_cash.ToString();
    monthly_rent_cash.TextChanged += CalculateRentPercent;
}

The important parts of this function are the async in the function definition and the await Task.Yield() after removing CalculateRentPercent from the monthly_rent_cash.TextChanged listener.

Without the await Task.Yield() the function would tell the app that it needs to remove the listener but it would not do it right away. The task would be queued up but put on hold until the current task finished. It would then proceed through the function and the monthly_rent_cash field would still fire CalculateRentPercent.

With the await Task.Yield() line, the app pauses its execution of the current function and lets the Task we just created to remove the TextChanged listener finish before it continues.

If you are new to C# or Xamarin, remember that anytime you have a line that uses await in your function definition, you need async as part of the function description.

There may be other solutions to this problem, but this is the easiest one I came across so far. If you know a better solution, email me at travis at evolvingdeveloper.com and let me know.

Found the solution on the Xamarin forums.

I Want to Be a Better Developer