Usman26 Usman26 - 17 days ago 7
Android Question

Xamarin TimePicker propertychanged event fired on load

I am developing a Xamarin app for android using Xamarin forms to create my layout. I have come across an issue with my time picker firing on load of my view cell.

What I am doing is creating a list view and then setting the item template to my custom view cell template. In my view cell template I am creating a TimePicker and binding a PropertyChanged event to it. I am also setting the TimePicker.Time property with information retrieved from the database. What seems to happen at this point is that my PropertyChanged event is fired for each item that will be displayed in the list view. This leads to multiple database calls that are not needed.

Is there a way to stop the PropertyChanged event being called until a property has actually been changed?

My code is below.

public class MyCell : ViewCell
{
private readonly TimePicker _myTimePicker;
public MyCell()
{
_myTimePicker = new TimePicker()
{
HorizontalOptions = LayoutOptions.EndAndExpand
};

_myTimePicker.SetBinding(TimePicker.TimeProperty, "StartTime");
_myTimePicker.PropertyChanged += MyTimePicker_PropertyChanged;

var viewLayout = new StackLayout()
{
HorizontalOptions = LayoutOptions.StartAndExpand,
Orientation = StackOrientation.Horizontal,
Padding = new Thickness(20),
Children = { _myTimePicker }
};
View = viewLayout;
}

private void MyTimePicker_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == TimePicker.TimeProperty.PropertyName && _myTimePicker.Time != TimeSpan.MinValue)
{
var dataAccess = new DataAccessLayer();
dataAccess.Update(myTimePicker.Time);
}
}
}


I'm not sure why the propertychanged event is fired multiple times and how to stop it firing until I actually pick a time. Any help would be appreciated.

Below is my code for the form to display the list view. All my xaml is defined in code. 'MyCell' uses the values returned from '_dataAccess.GetTimes()'.

public class TimeDetails : ContentPage
{
private ListView _listView;
private readonly DataAccessLayer _dataAccess = new DataAccessLayer();

protected override void OnAppearing()
{
_listView = new ListView
{
RowHeight = 80,
SeparatorColor = Color.Blue,
SeparatorVisibility = SeparatorVisibility.Default
};

_listView.ItemsSource = _dataAccess.GetTimes();
_listView.ItemTemplate = new DataTemplate(typeof(MyCell));
_listView.ItemSelected += ListView_ItemSelected;

Content = new StackLayout
{
VerticalOptions = LayoutOptions.FillAndExpand,
Children = { _listView }
};
}
}


The return type of _dataAcess.GetTimes() is List of TaskTime. The TaskTime model is shown below.

public class TaskTime
{
public int Id { get; set; }
public string Task { get; set; }
public TimeSpan StartTime { get; set; }
}

Answer
class MyCell : ViewCell
{
    private readonly TimePicker _myTimePicker;
    public MyCell()
    {
        _myTimePicker = new TimePicker()
        {
            HorizontalOptions = LayoutOptions.EndAndExpand
        };

        _myTimePicker.SetBinding(TimePicker.TimeProperty, "StartTime");
        _myTimePicker.PropertyChanged += MyTimePicker_PropertyChanged;
        _myTimePicker.Focused += _myTimePicker_Focused;

        var viewLayout = new StackLayout()
        {
            HorizontalOptions = LayoutOptions.StartAndExpand,
            Orientation = StackOrientation.Horizontal,
            Padding = new Thickness(20),
            Children = { _myTimePicker }
        };
        View = viewLayout;
    }

    bool myTimePickerSelected;
    private void _myTimePicker_Focused(object sender, FocusEventArgs e)
    {
        myTimePickerSelected = true;
    }

    private void MyTimePicker_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {

        if (e.PropertyName == TimePicker.TimeProperty.PropertyName && myTimePickerSelected)
        {
            //var dataAccess = new DataAccessLayer();
            //dataAccess.Update(myTimePicker.Time);
        }
    }
}
Comments