7

So I'm still debuting with Xamarin.Forms. So far so good, if I put aside a few pesky bugs I encountered. Here's the new guy. Maybe one of you could tell me if I'm doing something wrong.

Basically, I have a Xamarin.Forms.Switch on my interface, and I'm listening for changes in its state with the Toggled event. The doc says about this event: "Event that is raised when this Switch is toggled by the user."

Unfortunately, when I update the value of the switch programmatically, the event fires.

var mySwitch = new Switch ();
mySwitch.Toggled += (object sender, ToggledEventArgs e) => {
    Console.WriteLine ("Switch.Toggled event sent");
};
mySwitch.IsToggled = true;

Any way to prevent the event from firing / to know that it's not the user who triggered it?

aspyct
  • 3,625
  • 7
  • 36
  • 61
  • 1
    It should read like the SwitchCell Event, "Triggered when the switch has changed value". You can either hack it via a dirty flag set & check when programmatically updating your model or create an inherited class from it and create your own EventHandle Delegate that adds data to the TEventArgs so the receiver can see if the change is from a user interaction or not – SushiHangover Oct 06 '15 at 17:55
  • You could also set the true value before adding the event :) Or like @RobertN said save the old state around if you need to, or do some data binding might be easier. – JamesMontemagno Oct 07 '15 at 04:50
  • Switch control is a b*. The triggering of the event is good because it is toggled. It just shouldn't do that on the first databind (in my opinion). The way I worked around it is to do the databinding and attaching the event in C#. First I set IsToggled on the switch, then setBinding on the IsToggledProperty and after that I attach the event. Maybe this helps some other people here searching for answers. – Jørgen Jun 30 '16 at 14:37
  • Did you find solution on this? I also cant figure it out how to databind on first load especially? – Emil Jul 28 '16 at 22:14
  • @batmaci I haven't worked with Xamarin.Forms again, so no, no solution found. I guess I'd unregister the Toggled event before updating it programmatically. – aspyct Jul 29 '16 at 08:19

2 Answers2

5

The behavior you're experiencing is correct: every time the IsToggled property changes, the switch will fire the Toggled event.

I'm not sure if the Xamarin.Forms documentation has been updated recently, but as of today it says this about the Toggled event:

Event that is raised when this Switch is toggled

Sample Code

Here is sample code that prevents the Toggled event from being handled when the Toggled event is not fired by the user

enter image description here

using System;

using Xamarin.Forms;

namespace SwitchToggle
{
    public class SwitchPage : ContentPage
    {
        public SwitchPage()
        {
            var mySwitch = new Switch
            {
                IsToggled = true
            };
            mySwitch.Toggled += HandleSwitchToggledByUser;

            var toggleButton = new Button
            {
                Text = "Toggle The Switch"
            };
            toggleButton.Clicked += (sender, e) =>
            {
                mySwitch.Toggled -= HandleSwitchToggledByUser;
                mySwitch.IsToggled = !mySwitch.IsToggled;
                mySwitch.Toggled += HandleSwitchToggledByUser;
            };

            var mainLayout = new RelativeLayout();

            Func<RelativeLayout, double> getSwitchWidth = (parent) => parent.Measure(mainLayout.Width, mainLayout.Height).Request.Width;
            Func<RelativeLayout, double> getToggleButtonWidth = (parent) => parent.Measure(mainLayout.Width, mainLayout.Height).Request.Width;

            mainLayout.Children.Add(mySwitch,
                Constraint.RelativeToParent((parent) => parent.Width / 2 - getSwitchWidth(parent) / 2),
                Constraint.RelativeToParent((parent) => parent.Height / 2 - mySwitch.Height / 2)
            );
            mainLayout.Children.Add(toggleButton,
                Constraint.RelativeToParent((parent) => parent.Width / 2 - getToggleButtonWidth(parent) / 2),
                Constraint.RelativeToView(mySwitch, (parent, view) => view.Y + view.Height + 10)
            );

            Content = mainLayout;

        }

        async void HandleSwitchToggledByUser(object sender, ToggledEventArgs e)
        {
            await DisplayAlert(
                "Switch Toggled By User",
                "",
                "OK"
            );
        }
    }

    public class App : Application
    {
        public App()
        {
            MainPage = new NavigationPage(new SwitchPage());
        }
    }
}
Community
  • 1
  • 1
Brandon Minnick
  • 13,342
  • 15
  • 65
  • 123
  • 2
    Sure, it's "documentation accurate", but it's still a pain to have to unregister events every time I want to actuate the switch programatically. It doesn't make sense from a functionality point of view. – aspyct Nov 30 '16 at 10:54
  • Haha, yea, it's a pain. Hopefully this helped answer your question! Let me know if I can add anything more to help! – Brandon Minnick Nov 30 '16 at 16:26
  • Hi Aspyct! If you don't have any follow up questions, let's mark this question as Answered to help anyone in the future when they have a similar question. – Brandon Minnick Dec 01 '16 at 06:31
  • Ah well, fair enough I guess. – aspyct Dec 01 '16 at 10:00
4

Toggled event will every-time called, when you manually change the toggle that time also Toggled event will fire.

The solution is just set

mySwitch.Toggled -= HandleSwitchToggledByUser;

before you manually change toggle value, and write

mySwitch.Toggled += HandleSwitchToggledByUser;

after you manual change of toggle,

Hope, this will help you

Jere Käpyaho
  • 1,305
  • 1
  • 10
  • 29
MayankD
  • 91
  • 4
  • Good old Xamarin. As of Xamarin.Forms version 3.6.0.264807 this somehow does not work – pay Apr 03 '19 at 21:01