Forum Xamarin.Forms

Visual State Manager and custom properties

mdobricmdobric Member ✭✭

I am trying to set a custom property on a custom control using the Visual State Manager but I'm not having any luck so far. My custom control is just a label with an additional bindable property on it.

public class SelectableLabel : Label
{
    public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(SelectableLabel), false);

    public bool IsSelected
    {
        get { return (bool)GetValue(IsSelectedProperty); }
        set
        {
            Console.WriteLine($"MDO: {Text}.IsSelected_set={value}");
            SetValue(IsSelectedProperty, value);
        }
    }

I use this control inside a CollectionView to toggle the IsSelected property when the control enters the Selected visual state.

    <CollectionView
        x:Name="cv"
        ItemsSource="{Binding Names}"
        SelectionMode="Multiple"
        SelectedItems="{Binding SelectedNames, Mode=TwoWay}"
        VerticalOptions="Fill">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <local:SelectableLabel
                    x:Name="lblName"
                    Text="{Binding First}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup
                            x:Name="CommonStates">
                            <VisualState
                                x:Name="Normal">
                                <VisualState.Setters>
                                    <Setter
                                        Property="IsSelected"
                                        Value="False" />
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState
                                x:Name="Selected">
                                <VisualState.Setters>
                                    <Setter
                                        Property="IsSelected"
                                        Value="True" />
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                </local:SelectableLabel>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>

When I run this on an iOS simulator, I'm not seeing the setter being fired when the visual state changes to Selected. If I change the property in the setter to BackgroundColor or Text, I'm seeing the expected behavior. The problem seems specific to the custom property. I looked at the documentation for the Setter.Property and it states that the Setter can be applied to a BindableProperty which IsSelected is. Am I doing something wrong or does the VSM not support this functionality?

Answers

  • jezhjezh Member, Xamarin Team Xamurai

    Since property IsSelected is one state, and you want to change a control appearance according to a specific state, then what is the UI representation of this Label, is it a font change, or something else?

    Besides, there is a pre-defined Selected/UnSelected state for Label.

    You can check the following article, it should be helpful for you.
    https://xamgirl.com/understanding-visual-state-manager-in-xamarin-forms/

  • mdobricmdobric Member ✭✭

    The UI representation of the selected state is irrelevant. The code I posted is a simplified example to focus only on the issue I'm seeing. In the real use case, I'm not using a custom label and a lot of visual and non-visual properties are changed. To trigger all of this, I'm trying to set a custom property. The crux of the issue is that the VSM does not do that. The problem appears limited to custom properties. Here's another, even more simplified example :)

        public class SelectableEntry : Entry
        {
            public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(SelectableEntry), false);
    
            public bool IsSelected
            {
                get { return (bool)GetValue(IsSelectedProperty); }
                set
                {
                    Console.WriteLine($"MDO: {Text}.IsSelected_set={value}");
                    var color = value ? Color.LightBlue : Color.LightPink;
                    SetValue(IsSelectedProperty, value);
                    SetValue(BackgroundColorProperty, color);
                }
            }
        }
    

    Corresponding XAML:

            <local:SelectableEntry Text="First">
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="CommonStates">
                        <VisualState x:Name="Normal">
                            <VisualState.Setters>
                                <Setter
                                    Property="BackgroundColor"
                                    Value="LightBlue" />
                            </VisualState.Setters>
                        </VisualState>
                        <VisualState x:Name="Focused">
                            <VisualState.Setters>
                                <Setter
                                    Property="BackgroundColor"
                                    Value="LightPink" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
            </local:SelectableEntry>
    
         <local:SelectableEntry Text="Second">
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="CommonStates">
                        <VisualState x:Name="Normal">
                            <VisualState.Setters>
                                <Setter
                                    Property="IsSelected"
                                    Value="False" />
                            </VisualState.Setters>
                        </VisualState>
                        <VisualState x:Name="Focused">
                            <VisualState.Setters>
                                <Setter
                                    Property="IsSelected"
                                    Value="True" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
            </local:SelectableEntry>
    

    Setting focus to the first custom Entry changes the background color as expected. Doing the same for the second field does not. Notice that the only difference between these two fields is which property the setter is changing. I assume that I'm using VSM correctly because I'm seeing the expected change with the first control which makes me suspect that the issue is with how VSM handles custom properties.

Sign In or Register to comment.