Switch with IsToggled binding is throwing Toggled event on init when bound value is true

RileyTeigeRileyTeige USMember ✭✭
edited August 2017 in Xamarin.Forms

I have the following XAML:

<Switch 
       IsToggled="{Binding IsChecked}" 
       IsEnabled="true"
       Toggled="MyToggledEventHandler"
       VerticalOptions="CenterAndExpand" 
       HorizontalOptions="EndAndExpand" />

This switch exists as part of a custom listview viewcell template, and the records that supply the listview elements are loaded asynchronously as part of the ContentPage's OnAppearing() method. The ListView is hidden until these records have been loaded, as part of some MultiTriggers I have setup on the ListView to determine its IsVisible property. When the records get set into the BindableProperty to feed the listview, MyToggledEventHandler gets called for each record where IsChecked is true. This is not desirable because I have a server-side HTTP call that takes place as part of that event handler. How can I avoid this event being thrown while still taking advantage of XAML-only binding?

I should point out that I am not programmatically changing the IsChecked property at any point - it is true/false at the point that it gets set into the ListView ItemsSource property.

EDIT:
At the moment I am able to get around this with a secondary "checked" property in the record that is not a BindableProperty - when it doesn't match the bound property, then I know it was hand-toggled; when they do match, it's on init. I can use that trick to return early from MyToggledEventHandler. Definitely a hack, but it'll work until I get a better response.

Answers

  • KeenOnAppsKeenOnApps NLMember ✭✭

    I also spend some time getting frutstrated over this Switch control. In my opninion it shouldn't directly trigger the event on the first databind. The way I solved my way around is to set the events and databinding in the code-behind.
    First set the IsToggled property, then attach the databinding and after that set the Toggled event. Hope this helps someone searching for anwers.

  • JulienRosenJulienRosen CAMember ✭✭✭✭

    why not just monitor your IsChecked variable for changes, instead of using an event handler?

  • KeenOnAppsKeenOnApps NLMember ✭✭

    The IsChecked property on what object Julien?

  • JulienRosenJulienRosen CAMember ✭✭✭✭
    edited June 2016

    IsToggled="{Binding IsChecked}"

    If the value of the switch changes, so will IsChecked.

  • KeenOnAppsKeenOnApps NLMember ✭✭

    That would be the answer I guess. In my case that gave unwanted results but because of this I found that I updated the property in the background which triggered a change although the value itself was not changed. Thanks.

  • RajaRanganathanRajaRanganathan USMember ✭✭

    The Bind Property for IsToggled is not getting called on the event of Toggled. Is this expected? How did you solve this ? Can you please help me on this @KeenOnApps @JulienRosen

  • ChaseFlorellChaseFlorell CAInsider, University mod

    @RajaRanganathan said:
    The Bind Property for IsToggled is not getting called on the event of Toggled. Is this expected? How did you solve this ? Can you please help me on this @KeenOnApps @JulienRosen

    Can you show some code?

  • Tim.3500Tim.3500 USMember ✭✭

    @RileyTeige said:
    I have the following XAML:

    <Switch 
           IsToggled="{Binding IsChecked}" 
           IsEnabled="true"
           Toggled="MyToggledEventHandler"
           VerticalOptions="CenterAndExpand" 
           HorizontalOptions="EndAndExpand" />
    

    This switch exists as part of a custom listview viewcell template, and the records that supply the listview elements are loaded asynchronously as part of the ContentPage's OnAppearing() method. The ListView is hidden until these records have been loaded, as part of some MultiTriggers I have setup on the ListView to determine its IsVisible property. When the records get set into the BindableProperty to feed the listview, MyToggledEventHandler gets called for each record where IsChecked is true. This is not desirable because I have a server-side HTTP call that takes place as part of that event handler. How can I avoid this event being thrown while still taking advantage of XAML-only binding?

    I should point out that I am not programmatically changing the IsChecked property at any point - it is true/false at the point that it gets set into the ListView ItemsSource property.

    EDIT:
    At the moment I am able to get around this with a secondary "checked" property in the record that is not a BindableProperty - when it doesn't match the bound property, then I know it was hand-toggled; when they do match, it's on init. I can use that trick to return early from MyToggledEventHandler. Definitely a hack, but it'll work until I get a better response.

    How are you doing this? Share that part of the code, very frustrated right now with this toggle event... Thank you

  • uday_Suddhalauday_Suddhala USMember ✭✭

    Same scenario i came across!! it killed my time. whenever data comes from server side, if the boolean value for the switch we are appending is true. it automatically calling "toggled" event. this is not desired. we always want the event to be fired when we do perform some action on switch control.

    To overcome this , for each listview item cell i have created a boolean is check value and i'm restricting the toggled evnt implementation based on the flag.finally worked!!

  • HoussemDellaiHoussemDellai TNMember ✭✭
    edited May 2018

    What I have done is:
    private void Switch_BindingContextChanged(object sender, EventArgs e)
    {
    // we are not invoking Switch_Toggled directly from XAML for a reason!
    // that is in order to not fire it when Binding.
    if (!(sender is Switch s)) return;

            s.Toggled += Switch_Toggled;
        }
    
  • GuiZGuiZ Member
    edited September 2018

    I have the same problem. I bypass by disable the switch control and then when call the toogle event is call enable the switch and return;

            Switch sw = sender as Switch;
            if (!sw.IsEnabled)
            {
                sw.IsEnabled = true;
                return;
            }
    

    It's really a bad solution. Tips?

  • RobDurranceRobDurrance USMember ✭✭

    @HoussemDellai your solution did the trick! Thank you

  • yyouyyou Member ✭✭
    edited May 21

    Another solution is to create a private variable in the page class to indicate if it's at the initialization stage or not.

    private bool _initial;
    
    OnAppearing() {
        _initial = true;
       //get data from server and do data-binding.
        _initial = false;
    }
    
    MyToggledEventHandler(...) {
        if (_initial) { return; }
    
        //call server-side api
    }
    
Sign In or Register to comment.