Xamarin Forms is a wonderful ecosystem to develop cross platform mobile applications.
Like any platforms, it has limitations too, but yeah there are work arounds. At times you simply can contribute to the awesome “Open Source Xamarin Forms”
Today we will be discussing a small problem I faced in one of our projects, where Xamarin Forms Switch control fires “Toggled” event both when changed by user or programmatically. This was not ideal for our requirements.
So I planned to create a Custom Switch over the Original Switch.
Warning: This work around might not be the best way to do this.
To get started create a Class File, in my case “CustomSwitch”, inherit it from Switch class of Xamarin Forms.
We will create a IsCustomToggled property (which is Bindable Property), to use instead of IsToggled and CustomToggled instead of Toggled event.
Once we reach the constructor, we subscribe to the original Toggled event with our own function.
Also whenever IsCustomToggled is changed in code / program, we will Unsubscribe before setting original IsToggled, and then subscribe back to the event.
The CustomToggled event has CustomToggledEventArgs which contain the new value for switch and an bool “isUser” for indicating whether the action was result of user interaction or code change.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
public class CustomToggledEventArgs : EventArgs { public CustomToggledEventArgs(bool value, bool isuser) { Value = value; IsUser = isuser; } public bool Value { get; private set; } public bool IsUser { get; private set; } } public class CustomSwitch : Switch { private bool isUser { get; set; } = true; public bool IsCustomToggled { get => IsToggled; set { //The Order of Code is Very Important, We are removing Event Handler from Original Switch this.Toggled -= Handle_Toggled; //Setting IsToggled with IsCustomToggled IsToggled = value; //Invoking Custom Event with is User Property CustomToggled?.Invoke(this, new CustomToggledEventArgs(IsToggled, false)); //Enabling Event again this.Toggled += Handle_Toggled; } } public static readonly BindableProperty IsCustomToggledProperty = BindableProperty.Create("IsCustomToggled", typeof(bool), typeof(CustomSwitch), false, BindingMode.TwoWay); public event EventHandler<CustomToggledEventArgs> CustomToggled; public CustomSwitch() { //Subscribing to the original event this.Toggled += Handle_Toggled; } private void Handle_Toggled(object sender, ToggledEventArgs e) { //This even only fires when user is changing switch CustomToggled?.Invoke(this, new CustomToggledEventArgs(IsToggled, true)); } } |
Once the Custom Switch is ready, the usage at any place in project is straight forward,
from Xaml
1 |
<local:CustomSwitch IsCustomToggled="true" CustomToggled="Handle_Toggled"/> |
Samples and CustomSwitch available at GitHub
Hope this helps someone with same issue, in case of any queries do drop a mail to muhaymin at fantacode com where I am available Xamarin Consulting or use the comment section below.
Made a small change to the bindable property.
public static readonly BindableProperty IsCustomToggledProperty = BindableProperty.Create(
nameof(IsCustomToggled),
typeof(bool),
typeof(CustomSwitch),
false,
BindingMode.TwoWay,
propertyChanging: (bindable, oldValue, newValue) =>
{
if (oldValue != newValue)
{
var control = bindable as CustomSwitch;
control.IsCustomToggled = (bool)newValue;
}
}
);
I’m no Xamarin genius by any means but I never got the binding to actually work unless implementing the propertyChanging method.