I created a ContentView, called Switch, to host this slider as a custom control mainly so I can reuse the on and off visual states.
The ContentView contains a Label (which is there just for debugging) and a Syncfusion Switch plus some VisualStateManager stuff. The Label and the Switch are binded to BindableProperies in the code behind, with Switch using EventToCommandBehavior, so I doubt this is a Syncfusion problem.
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:core="clr-namespace:FEOD.Core;assembly=FEOD"
xmlns:buttons="clr-namespace:Syncfusion.XForms.Buttons;assembly=Syncfusion.Buttons.XForms"
mc:Ignorable="d"
x:Class="FEOD.Views.Components.Switch">
<ContentView.Content>
<StackLayout>
<Label Text="{Binding LabelText}" TextColor="Black" />
<buttons:SfSwitch VisualType="Cupertino" WidthRequest="50" HeightRequest="25">
<buttons:SfSwitch.Behaviors>
<core:EventToCommandBehavior EventName="StateChanged" Command="{Binding StateChangedCommand}"/>
</buttons:SfSwitch.Behaviors>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="On">
<VisualState.Setters>
<Setter Property="SwitchSettings">
<Setter.Value>
<buttons:DefaultSwitchSettings
x:TypeArguments="buttons:OnState"
ThumbBorderColor="#039CDE" ThumbColor="#FFFFFF"
TrackBorderColor="#039CDE" TrackColor="#039CDE"/>
</Setter.Value>
</Setter>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Off">
<VisualState.Setters>
<Setter Property="SwitchSettings">
<Setter.Value>
<buttons:DefaultSwitchSettings
x:TypeArguments="buttons:OffState"
ThumbBorderColor="#E77C21" ThumbColor="#FFFFFF"
TrackBorderColor="#E77C21" TrackColor="#E77C21"/>
</Setter.Value>
</Setter>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</buttons:SfSwitch>
</StackLayout>
</ContentView.Content>
Code behind Bindable's
using System.Windows.Input;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace FEOD.Views.Components
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Switch : ContentView
{
public static readonly BindableProperty StateChangedCommandProperty = BindableProperty.Create(
propertyName: nameof(StateChangedCommand),
returnType:typeof(ICommand),
declaringType:typeof(Switch),
defaultValue:default(ICommand),
defaultBindingMode: BindingMode.OneWay
);
public ICommand StateChangedCommand
{
get => (ICommand) GetValue(StateChangedCommandProperty);
set => SetValue(StateChangedCommandProperty, value);
}
public static readonly BindableProperty LabelTextProperty = BindableProperty.Create(nameof(LabelText), typeof(string), typeof(Switch), string.Empty, BindingMode.TwoWay);
public string LabelText
{
get => (string) GetValue(LabelTextProperty);
set => SetValue(LabelTextProperty, value);
}
public Switch()
{
InitializeComponent();
}
}
}
The ContentView is hosted in a ContentPage. Both of it's properties are set like this:
<components:Switch Grid.Column="1" LabelText="MY LABel" StateChangedCommand="{Binding CreatorOrContributorFinderCommand}" />
where LabelText is set in line as "MY LABel" and StateChangedCommand is set to the view model command "CreatorOrContributorFinderCommand". The page's BindingContext is set to an instance of the view model
public ICommand CreatorOrContributorFinderCommand { get; private set; }
private async Task OnCreatorOrContributorFinderChanged()
{
var a = 1;
}
constructor has this line:
CreatorOrContributorFinderCommand = new AsyncCommand(OnCreatorOrContributorFinderChanged);
Note: AsyncCommand comes from https://johnthiriet.com/mvvm-going-async-with-async-command
I cannot figure out why neither the Label nor the command are doing anything. During debugging, the LabelText doesn't show up
When I slide the switch, this breakpoint in EventToCommandBehavior shows that no command is tied to the event. The null command prevents the handler in the viewmodel from getting called.
After being confounded on this and trolling through the EventToCommandBehavoir source code and dozens of StackOverflow postings, I finally found the problems.
I found two things to watch out for:
The first is that EventToCommandBehavoir only wants a Xamarin.Forms.Command, not just any ICommand.
The second, thanks very much to this post, the ContentView must have this in its constructor for commands to work (though, not for other types like text).
Content.BindingContext = this;
Because there are a several ICommand implementations (useful especially if you want AsyncCommand) and that Labels and such work fine without setting Content.BindingContext, it is very easy to get confounded by EventToCommandBehavior.