Issue with Custom Bindable Properties in CustomSwitch Control Inheriting from SfSwitch

Context: 

I have created a custom switch control by inheriting from SfSwitch and defined several bindable properties to manage the switch's visual settings dynamically based on the IsOn property. The relevant code is as follows:

using Syncfusion.Maui.Buttons;

public class CustomSwitch : SfSwitch
{
public CustomSwitch()
{
PropertyChanged += OnCustomSwitchPropertyChanged;
UpdateSwitchSettings(); // Initial setup
}

public static readonly BindableProperty CustomSwitchSettingsProperty =
BindableProperty.Create(nameof(CustomSwitchSettings), typeof(SwitchSettings), typeof(CustomSwitch), default(SwitchSettings), propertyChanged: OnCustomSwitchSettingsChanged);

public SwitchSettings CustomSwitchSettings
{
get => (SwitchSettings)GetValue(CustomSwitchSettingsProperty);
set => SetValue(CustomSwitchSettingsProperty, value);
}

public static readonly BindableProperty ThumbBackgroundProperty =
BindableProperty.Create(nameof(ThumbBackground), typeof(Color), typeof(CustomSwitch), default(Color));

public static readonly BindableProperty ThumbStrokeProperty =
BindableProperty.Create(nameof(ThumbStroke), typeof(Color), typeof(CustomSwitch), default(Color));

public static readonly BindableProperty TrackBackgroundProperty =
BindableProperty.Create(nameof(TrackBackground), typeof(Color), typeof(CustomSwitch), default(Color));

public static readonly BindableProperty TrackStrokeProperty =
BindableProperty.Create(nameof(TrackStroke), typeof(Color), typeof(CustomSwitch), default(Color));

public Color ThumbBackground
{
get => (Color)GetValue(ThumbBackgroundProperty);
set => SetValue(ThumbBackgroundProperty, value);
}

public Color ThumbStroke
{
get => (Color)GetValue(ThumbStrokeProperty);
set => SetValue(ThumbStrokeProperty, value);
}

public Color TrackBackground
{
get => (Color)GetValue(TrackBackgroundProperty);
set => SetValue(TrackBackgroundProperty, value);
}

public Color TrackStroke
{
get => (Color)GetValue(TrackStrokeProperty);
set => SetValue(TrackStrokeProperty, value);
}

private void OnCustomSwitchPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(IsOn))
{
UpdateSwitchSettings();
}
}

private static void OnCustomSwitchSettingsChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is CustomSwitch customSwitch && newValue is SwitchSettings newSettings)
{
customSwitch.SwitchSettings = newSettings;
}
}

private void UpdateSwitchSettings()
{
if ((bool)IsOn)
{
CustomSwitchSettings = new SwitchSettings
{
ThumbBackground = Color.FromArgb("#FF029BFF"),
ThumbStroke = Color.FromArgb("#FF029BFF"),
TrackBackground = Color.FromArgb("#22029BFF"),
TrackStroke = Color.FromArgb("#22029BFF"),
};
}
else
{
CustomSwitchSettings = new SwitchSettings
{
ThumbBackground = Color.FromArgb("#FFFF0199"),
ThumbStroke = Color.FromArgb("#FFFF0199"),
TrackBackground = Color.FromArgb("#22FF0199"),
TrackStroke = Color.FromArgb("#22FF0199"),
};
}
}
}

Now I will use it like this:
<!-- In my page content --> <customControl:CustomSwitch Grid.Column="1" IsOn="True" />

Problem:

Even after setting up the bindable properties and event handlers, the CustomSwitch control does not apply the SwitchSettings as expected. To achieve the desired effect, I’ve had to use the VisualStateManager in XAML. Additionally, I need to include xmlns:switch="clr-namespace:Syncfusion.Maui.Buttons;assembly=Syncfusion.Maui.Buttons" in the consuming app.

This namespace is already added in the CustomSwitch control, but without explicitly adding it in the XAML page where the control is used, I’m unable to access the SwitchSettings property.

<ContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:switch="clr-namespace:Syncfusion.Maui.Buttons;assembly=Syncfusion.Maui.Buttons">
<control:CustomSwitch IsOn="{Binding SelectedViolationItem.CorrectOnSite}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="On">
<VisualState.Setters>
<Setter Property="SwitchSettings">
<Setter.Value>
<switch:SwitchSettings
ThumbBackground="{StaticResource SwitchThumbOnColor}"
ThumbStroke="{StaticResource SwitchThumbOnColor}"
TrackBackground="{StaticResource SwitchTrackOnColor}"
TrackStroke="{StaticResource SwitchTrackOnColor}"/>
</Setter.Value>
</Setter>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Off">
<VisualState.Setters>
<Setter Property="SwitchSettings">
<Setter.Value>
<switch:SwitchSettings
ThumbBackground="{StaticResource CommonLightGrayColor}"
ThumbStroke="{StaticResource CommonLightGrayColor}"
TrackBackground="{StaticResource MidGray}"
TrackStroke="{StaticResource MidGray}"/>
</Setter.Value>
</Setter>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</control:CustomSwitch>
</ContentPage>

Question:

Why are the bindable properties not working as intended in this scenario? How can I ensure that the CustomSwitchSettings are applied based on the IsOn property without relying on the VisualStateManager? 

Any guidance or suggestions to resolve this issue would be greatly appreciated.


1 Reply

BV Brundha Velusamy Syncfusion Team August 26, 2024 09:44 AM UTC

Hi Divyesh Bhatt,


Query 1: I need to include xmlns:switch="clr-namespace:Syncfusion.Maui.Buttons;assembly=Syncfusion.Maui.Buttons" in the consuming app. This namespace is already added in the CustomSwitch control, but without explicitly adding it in the XAML page where the control is used, I’m unable to access the SwitchSettings property.


We want to inform you that, in your code snippet, you have initialized the CustomSwitchSettings as a property so this will not be accessible to define switch settings properties as you intended. To customize the SwitchSettings of the SfSwitch or your CustomSwitch control, you need to include the relevant namespace in the XAML page where the control is used. If you want to access SwitchSettings without explicitly using the Syncfusion namespace, you can define a separate CustomSwitchSettings class as shown in the below code snippet.


Here's an example code snippet:


SwitchSettingsOn:

public class SwitchSettingsOn : SwitchSettings

{

   public SwitchSettingsOn()

   {

      //Initialize the properties

   }

}


Xaml:

<control:CustomSwitch IsOn="{Binding SelectedViolationItem.CorrectOnSite}">

    <VisualStateManager.VisualStateGroups>

        <VisualStateGroup x:Name="CommonStates">

            <VisualState x:Name="On">

                <VisualState.Setters>

                    <Setter Property="SwitchSettings">

                        <Setter.Value>

                            <control:SwitchSettingsOn

                            ThumbBackground="{StaticResource SwitchThumbOnColor}"

                            ThumbStroke="{StaticResource SwitchThumbOnColor}"

                            TrackBackground="{StaticResource SwitchTrackOnColor}"

                            TrackStroke="{StaticResource SwitchTrackOnColor}"/>

                        </Setter.Value>

                    </Setter>

                </VisualState.Setters>

            </VisualState>

           

        </VisualStateGroup>

    </VisualStateManager.VisualStateGroups>

</control:CustomSwitch>


Query 2: Why are the bindable properties not working as intended in this scenario? How can I ensure that the CustomSwitchSettings are applied based on the IsOn property without relying on the VisualStateManager?


We want to inform you that, SwitchSettings cannot be directly customized based on the IsOn property. Instead, you need to use the VisualStateManager to handle different states.


Please refer to the below help documentation link for more details:

Visual state manager in .NET MAUI Switch (SfSwitch) | Syncfusion


To achieve your requirement,  we recommend utilizing the VisualStateManager in the custom control, as shown in the below code snippet. This will helps to apply the SwitchSettings to the switch based on its on and off states.


CustomSwitch:

public class CustomSwitch : SfSwitch

{

    public CustomSwitch()

    {   

        UpdateSwitchSettings();  // Initial setup

    }

    private void UpdateSwitchSettings()

    {

        SwitchSettings onStyle = new SwitchSettings();

        onStyle.TrackBackground = (Color.FromRgba("#22029BFF"));

        onStyle.ThumbBackground = (Color.FromRgba("#FF029BFF"));

        onStyle.TrackStroke = Color.FromRgba("#22029BFF");

        onStyle.ThumbStroke = Color.FromRgba("#FF029BFF");

 

        SwitchSettings offStyle = new SwitchSettings();

        offStyle.TrackBackground = (Color.FromRgba("#22FF0199"));

        offStyle.ThumbBackground = (Color.FromRgba("#FFFF0199"));

        offStyle.TrackStroke = Color.FromRgba("#22FF0199");

        offStyle.ThumbStroke = Color.FromRgba("#FFFF0199");

 

        VisualStateGroupList visualStateGroupList = new VisualStateGroupList();

        VisualStateGroup commonStateGroup = new VisualStateGroup();

 

        VisualState onState = new VisualState { Name = "On" };

        onState.Setters.Add(new Setter { Property = SfSwitch.SwitchSettingsProperty, Value = onStyle });

 

        VisualState offState = new VisualState { Name = "Off" };

        offState.Setters.Add(new Setter { Property = SfSwitch.SwitchSettingsProperty, Value = offStyle });

 

        commonStateGroup.States.Add(onState);

        commonStateGroup.States.Add(offState);

 

        visualStateGroupList.Add(commonStateGroup);

        VisualStateManager.SetVisualStateGroups(this, visualStateGroupList);

    }

}


Xaml:

<StackLayout>

    <control:CustomSwitch/>

</StackLayout>


We have drafted a simple sample based on this approach and attached the sample for your reference. Please review it and let us know if you have any concerns.


We hope this helps! If you have any further questions or need additional assistance, please feel free to reach out.


If your requirements differ from this suggested solution, please provide more detailed specifications, it would help us investigate and propose a more accurate solution.


Regards,

Brundha V


Attachment: SfSwitchMaui_f2ca8864.zip

Loader.
Up arrow icon