Search code examples
xamarinxamarin.formstoggleinfinite-loop

Xamarin forms switch events lead to infinte loop - Group switches


I am trying to develop an app using Xamarin.Forms. At a certain point I am trying to have multiple switches that are grouped. This is to say that when one switch is toggled, every other switch needs to be untoggled and, at the same time, there needs to be at least one switch always toggled. This is to say that tapping on a switch that is already toggled should not change anything.T

Now my problem is that Xamarin.forms Toggled event for switches can be fired from the UI, but is also fired programmatically. I thought I had found a way around this problem, but still by doing: -If the switch was turned on, turn off all others and do application stuff. -else if a switch was turned off, check if there are any others that are on. If not, turn the switch back on. If yes, do nothing.

A sample code for two switches could be:

private void OnFirstToggled(object sender, EventArgs args)
{
   if(FirstSwitch.isToggled)
  {
     //Application stuff.
     SecondSwitch.isToggled = false;
  }
  else if (!SecondSwitch.isToggled)
  {
      FirstSwitch.isToggled = true;
  }
}

private void OnSecondToggled(object sender, EventArgs args)
{
   if(SecondSwitch.isToggled)
  {
     //Application stuff.
     FirstSwitch.isToggled = false;
  }
  else if (!FirstSwitch.isToggled)
  {
      SecondSwitch.isToggled = true;
  }
}

This solution results in an infinite loop when an already toggled switch is tapped. In fact, the isToggled property of the switch alternates between true and false infinitely. However when debugging the other event never seems to be fired (or at least my debugger does not see it). This is why I don't understand where the isToggled property is changed after that first tap.

I know this is probably a very simple issue, but I cannot seem to find the solution somewhere online. Can anyone see the problem or recommend a better, common way to implement this?


Solution

  • I write a simple solution to you to always keep one Switch open from a Switch group.

    Let's first add three switch for test, make sure these Switch will fire the same event of Toggled:

    <StackLayout>
        <!-- Place new controls here -->
        <Switch Toggled="Switch_Toggled" x:Name="FirstSwitch"/>
        <Switch Toggled="Switch_Toggled" x:Name="SecondSwitch"/>
        <Switch Toggled="Switch_Toggled" x:Name="ThirdSwitch"/>
    
    </StackLayout>
    

    In the code behind, I add those Switches into a list, and loop them in Switch_Toggled event to open/close the Switches:

    public partial class MainPage : ContentPage
    {
    
        List<Switch> switchList;// To store all your Switches
    
        bool isLooping; //To make sure the Switch_Toggled metod not fired a second time during one toogle event
    
        public MainPage()
        {
            InitializeComponent();
    
            switchList = new List<Switch>();
    
            switchList.Add(FirstSwitch);
            switchList.Add(SecondSwitch);
            switchList.Add(ThirdSwitch);
    
    
            isLooping = false;
        }
    
        private void Switch_Toggled(object sender, ToggledEventArgs e)
        {
            //To make sure the Switch_Toggled metod not fired a second time during one toogle event
            if (isLooping == true)
            {
                return;
            }
    
            isLooping = true;
    
            Switch clickSwitch = sender as Switch;
            clickSwitch.IsToggled = true;
    
            foreach (var tempSwitch in switchList)
            {
                if (tempSwitch != clickSwitch)
                {
                    if (tempSwitch.IsToggled == true)
                    {
                        tempSwitch.IsToggled = false;
                    }
                }
            }
    
            isLooping = false;
        }    
    }
    

    You can try this solution and feel free to ask me any question if you don't understand.