alexrainman / SegmentedControl

MIT License
86 stars 38 forks source link

SelectedSegment Binding Broken Within DataTemplate #74

Open Jyosua opened 6 years ago

Jyosua commented 6 years ago

Hi! We were trying to use this control within the DataTemplate of a ListView and found that the SelectedSegment binding was not working after the first change on Android. On iOS, it only seems to stop working if you manually toggle the control before programmatically changing the bound property. I was able to reproduce this in a small sample project. Below are the MainPage.xaml, corresponding codebehind, and supporting code that I reproduced this on.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:SampleApp2"
             xmlns:abstractions="clr-namespace:SegmentedControl.FormsPlugin.Abstractions;assembly=SegmentedControl.FormsPlugin.Abstractions"
             x:Class="SampleApp2.MainPage">
    <StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand">
        <Button Text="Check All" Clicked="OnClick" />
        <ListView HasUnevenRows="False" HorizontalOptions="FillAndExpand" BackgroundColor="Black"
                    VerticalOptions="FillAndExpand" x:Name="AttendeeList" RowHeight="80">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell Height="100">
                        <StackLayout VerticalOptions="CenterAndExpand">
                            <abstractions:SegmentedControl x:Name="AttendanceControl" SelectedSegment="{Binding Status}" SelectedTextColor="White" TintColor="{Binding StatusColor}">
                                <abstractions:SegmentedControl.Children>
                                    <abstractions:SegmentedControlOption Text="Missing"/>
                                    <abstractions:SegmentedControlOption Text="Turned"/>
                                    <abstractions:SegmentedControlOption Text="Attended"/>
                                </abstractions:SegmentedControl.Children>
                            </abstractions:SegmentedControl>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace SampleApp2
{
    public partial class MainPage : ContentPage
    {
                private ObservableCollection<Attendee> _attendees;

        public MainPage()
        {
            InitializeComponent();
            _attendees = new ObservableCollection<Attendee>() { new Attendee(0), new Attendee(1), new Attendee(2) };
            AttendeeList.ItemsSource = _attendees;
        }

        public void OnClick(object sender, EventArgs e)
        {
            foreach (var item in _attendees)
                item.Status = item.Status == 2 ? 0 : 2;
        }
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using Xamarin.Forms;

namespace SampleApp2
{
    public class Attendee : INotifyPropertyChanged
    {
        public Attendee(int status)
        {
            Status = status;
        }

        private int _status;
        public int Status
        {
            get => _status;
            set
            {
                _status = value;
                OnPropertyChanged();
                OnPropertyChanged(nameof(StatusColor));
            }
        }

        public Color StatusColor
        {
            get
            {
                switch (Status)
                {
                    case 0:
                        return Color.Gray;
                    case 1:
                        return Color.Yellow;
                    case 2:
                        return Color.Green;
                    default:
                        return Color.Gray;
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

The TintColor binding appears to continue to work in any case. It's just the SelectedSegment binding that stops working.

Jyosua commented 6 years ago

I put the entire sample project up in a repository here: https://github.com/Jyosua/SegmentedControlBug_SampleProject

ryanherman commented 6 years ago

@alexrainman Are you able to look into this? I am also having this problem... Thank you!

ryanherman commented 6 years ago

Turns out it is an easy fix...

SelectedSegment="{Binding Status, Mode=TwoWay}"