Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I stop a Toggled Event on a switch from being fired as a page is loaded?

My application has a switch set up in XAML and backend C# code that responds to the toggle event

<ViewCell x:Name="ss">
   <Switch x:Name="ssSwitch" Toggled="SsSwitch"   />
</ViewCell>

void SsSwitch(object sender, ToggledEventArgs e) {
    // Code to update database here
}

When the page first loads I notice that the SwSwitch Toggled event is called.

Is there some way that I can stop this happening as there is no reason to do an update of the database on start up.

like image 937
Alan2 Avatar asked Aug 22 '17 15:08

Alan2


2 Answers

Option-1: Use property setter in ViewModel

If you are using MVVM - the simplest option to resolve this would be to use property setter to detect value update (as mentioned on this link). But this option doesn't work if you want to call awaitable methods here. Also, as a best practice it is recommended that properties shouldn't implement any time consuming operations.

bool _isToggled;
public bool IsToggled 
{ 
    get 
    {
        return _isToggled;
    } 
    set
    {
        _isToggled = value;
        // Add your update code here
    }
}

Option-2: Use PropertyChanged event in ViewModel

The next option would be to subscribe to PropertyChanged event in your viewmodel and appropriately handle it. This allows you to define async handlers which in turn can await asynchronous methods.

// Subscribe to event while constructing/assigning viewmodel
// viewCellVM.PropertyChanged += CategoryVM_PropertyChanged;

async void ViewCellVM_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if(e.PropertyName == nameof(ViewCellVM.IsToggled))
    {
        //call update code here
        //await DB.Update();
    }
}

Option-3: Override OnAppearing() in ViewCell

Another option is to make sure that the Toggled event handler is assigned after the BindingContext is updated on the ViewCell. So, I did a quick experiment to track the order Handle_Toggled, OnBindingContextChanged, OnAppearing methods are called while loading the view. The order turned out to be:

Handle_Toggled
OnBindingContextChanged
OnAppearing

Hence, assigning the handler in OnAppearing method (in ViewCell's code-behind) should also work for this case:

//XAML:<Switch x:Name="switchBtn" IsToggled="{Binding IsToggled}" />
protected override void OnAppearing()
{
    base.OnAppearing();

    switchBtn.Toggled += Handle_Toggled;
    Debug.WriteLine("OnAppearing");
}

protected override void OnDisappearing()
{
    base.OnDisappearing();

    switchBtn.Toggled -= Handle_Toggled;
    Debug.WriteLine("OnDisappearing");
}

This way Handle_Toggled will only be called when the user toggles the switch.

like image 162
Sharada Gururaj Avatar answered Oct 20 '22 17:10

Sharada Gururaj


With your code above the Switch shouldn't trigger the event on first start. It triggers only if you have bound your IsToggled property with your ViewModel! The reason for that is, that the Page is initialized first, the ViewModel toggles the Switch and then the event is getting fired.

First solution would be to handle the IsToggled property and the Toggled event both from the code-behind (not recommended if you are mvvm-ing your code). Better solution would be to handle both from the ViewModel.

The problem is, that the Switch Control doesn't have a Command property. You have to use a Behaviour to bind to a Command. Sharada Gururaj already posted a Link above with a good explanation.

Here is the short Solution form Sharada Gururajs stackoverflow link: Xamarin Forms Switch Toggled event doesn't bind with viewmodel

<Switch IsToggled="{Binding IsToggled}">
<Switch.Behaviors>
    <behaviors:EventHandlerBehavior EventName="Toggled">
    <behaviors:InvokeCommandAction Command="{Binding ToggleSwitchCommand}" />
    </behaviors:EventHandlerBehavior>
</Switch.Behaviors>

Further Informations:

  • https://blog.xamarin.com/turn-events-into-commands-with-behaviors/
  • https://forums.xamarin.com/discussion/64374/switch-with-istoggled-binding-is-throwing-toggled-event-on-init-when-bound-value-is-true
like image 24
Tomislav Erić Avatar answered Oct 20 '22 15:10

Tomislav Erić