0
votes

I am trying to run the clock for lets say 5 cities, like each city in each cell of the listview and clock(local time) running besides city name. (Screenshot attached below)

I am getting the local time of the city using offset value of that city.

And for the clock to move I used StartTimer, so that the time will change for every second.

Currently I am getting the offsetValue as zero there and so getting the UTC time there for all the cities as same.

I want all the cities with the local time displaying beside city name and the clock must move for every second.

Any help will be appreciated .. Thanks in advance.

Sample screenshot of cities with respective clocks

List<OffsetItems> items = new List<OffsetItems>();
        items.Add(new OffsetItems() { CityName = "Hyderabad", Offset = 5.5 });
        items.Add(new OffsetItems() { CityName = "London", Offset = 1 });
        items.Add(new OffsetItems() { CityName = "Tokyo", Offset = 9 });
        items.Add(new OffsetItems() { CityName = "New York", Offset = -5 });
        items.Add(new OffsetItems() { CityName = "Dubai", Offset = 4 });


        ListView lv = new ListView
        {
            SeparatorVisibility = SeparatorVisibility.None,
            ItemsSource = items,

            ItemTemplate = new DataTemplate(() =>
            {

                Label cityL = new Label()
                {
                    TextColor = Color.Black,
                    HorizontalTextAlignment = TextAlignment.Start,
                    FontSize = Device.GetNamedSize(NamedSize.Small, new Label())
                };
                Label timeL = new Label()
                {
                    TextColor = Color.Black,
                    HorizontalTextAlignment = TextAlignment.Center,
                    FontSize = Device.GetNamedSize(NamedSize.Small, new Label())
                };
                cityL.SetBinding<OffsetItems>(Label.TextProperty, indexer => indexer.CityName);

                Label ll = new Label();
                Device.StartTimer(TimeSpan.FromSeconds(1), () => {

                    ll.SetBinding<OffsetItems>(Label.TextProperty, indexer => indexer.Offset);
                    double offsetValue = Convert.ToDouble(ll.Text);

                    timeL.Text = DateTime.UtcNow.AddHours(offsetValue).ToString("hh:mm:ss tt, ddd dd-MMM-yyyy");
                    return true; 
                });

                return new ViewCell
                {
                    View = new StackLayout
                    {
                        Orientation = StackOrientation.Horizontal,
                        Children =
                            {
                            cityL,
                            timeL
                        }
                    }
                };
            })
        };

        Content = new StackLayout
        {
            Children = {
                lv
            }
        };
2

2 Answers

0
votes

I have added the code for what Alessandro has mentioned and that is how it should be done.

class OffsetItems : INotifyPropertyChanged
    {
        private double _offset;
        private string _time;
        private string _cityName;

        public string CityName
        {
            get { return _cityName; }
            internal set
            {
                _cityName = value;
                OnPropertyChanged("CityName");
            }
        }

        public string Time
        {
            get { return _time; }
            internal set
            {
                _time = value;
                OnPropertyChanged("Time");
            }
        }

        public double Offset
        {
            get { return _offset; }
            internal set
            {
                _offset = value;
                OnPropertyChanged("Offset");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public partial class MainPage : ContentPage
    {
        ObservableCollection<OffsetItems> Items = new ObservableCollection<OffsetItems>();

        public MainPage()
        {
            InitializeComponent();

            Items.Add(new OffsetItems() { CityName = "Hyderabad", Offset = 5.5 });
            Items.Add(new OffsetItems() { CityName = "London", Offset = 1 });
            Items.Add(new OffsetItems() { CityName = "Tokyo", Offset = 9 });
            Items.Add(new OffsetItems() { CityName = "New York", Offset = -5 });
            Items.Add(new OffsetItems() { CityName = "Dubai", Offset = 4 });

            var lv = new ListView
            {
                ItemsSource = Items,
                SeparatorVisibility = SeparatorVisibility.None,
                ItemTemplate = new DataTemplate(() =>
                {

                    Label cityL = new Label()
                    {
                        TextColor = Color.Black,
                        HorizontalTextAlignment = TextAlignment.Start,
                        FontSize = Device.GetNamedSize(NamedSize.Small, new Label())
                    };
                    Label timeL = new Label()
                    {
                        TextColor = Color.Black,
                        HorizontalTextAlignment = TextAlignment.Center,
                        FontSize = Device.GetNamedSize(NamedSize.Small, new Label())
                    };
                    cityL.SetBinding<OffsetItems>(Label.TextProperty, indexer => indexer.CityName);
                    timeL.SetBinding<OffsetItems>(Label.TextProperty, indexer => indexer.Time, BindingMode.OneWay);

                    Label ll = new Label();

                    return new ViewCell
                    {
                        View = new StackLayout
                        {
                            Orientation = StackOrientation.Horizontal,
                            Children =
                            {
                                cityL,
                                timeL
                            }
                        }
                    };
                })
            };

            Content = new StackLayout
            {
                Children = {
                    lv
                }
            };
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();
            Device.StartTimer(TimeSpan.FromSeconds(1), () =>
            {
                Items.ForEach(row => row.Time = DateTime.UtcNow.AddHours(row.Offset)
                    .ToString("hh:mm:ss tt, ddd dd-MMM-yyyy"));
                return true;
            });
        }
    }

*Foreach is an extension which i have it in private lib. Hope this code helps

0
votes

I think you should not have a StartTimer in your template. You should have a StartTimer (for example) in OnAppearing method.

When the StartTimer event rises, you should change a "Time" property you should have in your Model (changing the "Time" property to ALL items in your ObservableCollection... you should not use a "List"). Bind this "Time" property to your "timeL" field. Now your timeL fields should update automatically if you implement INotifyPropertyChanged.