秒表列表 - 由于绑定,重新启动开始所有计时器

List of Stopwatches - restarting begins all timers due to binding

希望您能提供帮助...我有一个活动列表,这些活动使用秒表来跟踪每个 activity 持续时间。当我点击列表中的 activity 时,它会启动所点击的 activity 的秒表,当我再次点击 activity 行时,它会停止并重置秒表。

然而,当我点击另一个 activity 时,虽然它实际上只是更新在后端点击的 activity 的持续时间,但前端 UI 会更新所有活动计时器具有相同的 activity 时间,因为它们绑定到相同的 activityduration 元素。我不知道如何只更改前端点击的 activity 的 activity 持续时间。如果没有 re-structuring 我的 model/collection,谁能建议如何做到这一点?还是我必须在 collection 中为 activity 名称创建一个子嵌套?

隐藏代码中的点击事件:-


public async void OnActivityTap(object sender, EventArgs e)
        {
            var item = (ViewCell)sender;
            UserActivities.Activities myactivitiesModel = item.BindingContext as UserActivities.Activities;

            if (myactivitiesModel == null)
            {return;}

            // OnPropertyChanged("ActivityDuration");
            // mystopwatch.Reset();
            //ViewModel.getUserActivities();

            foreach (var x in ViewModel.UserActivitiesList) {

                if(x.ActivityName == myactivitiesModel.ActivityName) {
                        int seconds = 1;

                    //if the activity is not enabled and the activity is tapped
                    if (myactivitiesModel.ActivityEnabled == false)
                    {
                        //enable the activity and start the stopwatch
                        myactivitiesModel.ActivityEnabled = true;

                        //Get the current duration and add it onto the stopwatch start time
                        ts =  x.ActivityDuration; 

                        //Reset the stopwatch back to zero
                                       
                        mystopwatch = new Stopwatch();
                        //Start the stopwatch
                        mystopwatch.Reset();
                        mystopwatch.Start(); 

                        while (myactivitiesModel.ActivityEnabled == true)
                        {
                            Device.StartTimer(TimeSpan.FromSeconds(seconds), () =>
                            {
                          
                             myactivitiesModel.ActivityDuration = (mystopwatch.Elapsed + ts);
                  
                                return true;
                            });

                            return;
                        }
             
                    }
                    else if (myactivitiesModel.ActivityEnabled == true)
                    {
                        //disable the activity and stop the stopwatch
                        x.ActivityEnabled = false;

                        //Stop the clock
                        mystopwatch.Stop();
                       
                        
                        //Store activity time stopped
                        await MongoService.UpdateUserActivityTime(userIdentity, myactivitiesModel.ActivityName, x.ActivityDuration);

                        //Store the time stopped in the UserActivitiesList binded to the UI list
                        x.ActivityDuration = myactivitiesModel.ActivityDuration;
                        OnPropertyChanged("ActivityDuration");

                        return;
  
                    }

                } //end of if activityName Tapped
  
            } //end of foreach

        } //end of OnTap Activity

型号:


public class UserActivities : INotifyPropertyChanged
    {

        [BsonId, BsonRepresentation(BsonType.ObjectId)]
        public string Id { get; set; }

        string _foreignUserID;
        [BsonElement("foreignUserID")]
        public string foreignUserID
        {
            get => _foreignUserID; set
            {
                if (_foreignUserID == value)
                    return;

                _foreignUserID = value;

                HandlePropertyChanged();
            }
        }

        [BsonElement("activities")]
        public ObservableCollection<Activities> UserTimedActivities { get; set; }

        public class Activities : INotifyPropertyChanged
        {
            

            string _activityName;
            [BsonElement("activityName")]            
            public string ActivityName
            {
                get => _activityName; set
                {
                    if (_activityName == value)
                        return;

                    _activityName = value;

                    HandlePropertyChanged();
                }
            }

            TimeSpan _activityDuration;
            [BsonElement("activityDuration")]            
            public TimeSpan ActivityDuration
            {
                get => _activityDuration; set
                {
                    if (_activityDuration == value)
                        return;

                    _activityDuration = value;
                    HandlePropertyChanged();
                }
            }

            TimeSpan _activityGoalDuration;
            [BsonElement("activityGoalDuration")]            
            public TimeSpan ActivityGoalDuration
            {
                get => _activityGoalDuration; set
                {
                    if (_activityGoalDuration == value)
                        return;

                    _activityGoalDuration = value;

                    HandlePropertyChanged();
                }
            }

            Boolean _activityEnabled;
            [BsonElement("activityEnabled")]            
            public Boolean ActivityEnabled
            {
                get => _activityEnabled; set
                {
                    if (_activityEnabled == value)
                        return;

                    _activityEnabled = value;

                    HandlePropertyChanged();
                }
            }

            public Activities(string activityname, TimeSpan activityduration, TimeSpan activitygoalduration, Boolean activityenabled ) {
                ActivityName = activityname;
                ActivityDuration = activityduration;
                ActivityGoalDuration = activitygoalduration;
                ActivityEnabled = activityenabled;
            }

            void HandlePropertyChanged([CallerMemberName] string propertyName = "")
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }

            public event PropertyChangedEventHandler PropertyChanged;
        }

        public UserActivities(ObservableCollection<Activities> usertimedactivities)
        {
            UserTimedActivities = usertimedactivities;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        void HandlePropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

ViewModel方法编译列表-

public async void getUserActivities()
        {
            var userActivities = await MongoService.GetUserActivityData(userIdentity);

            try
            {
                if (IsBusy)
                    return;
                IsBusy = true;
                UserActivitiesList.Clear();

                foreach (var x in userActivities)
                {
                    foreach(var y in x.UserTimedActivities) {

                        //foreach (var y in x.userActivities)
                        UserActivitiesList.Add(y);
                    }
                }
            }
            catch (Exception ex)
            {
                IsBusy = false;
                Debug.WriteLine(ex);
            }
            finally
            {
                IsBusy = false;
            }
        }

2。 Jason 建议的替代计时器方法(不获取经过时间或更新 UI):

 public async void OnActivityTap(object sender, EventArgs e)
        {
            var item = (ViewCell)sender;
            UserActivities.Activities myactivitiesModel = item.BindingContext as UserActivities.Activities;

            if (myactivitiesModel == null)
            { return; }

            foreach (var x in ViewModel.UserActivitiesList)
            {

                if (x.ActivityName == myactivitiesModel.ActivityName)
                {
                    if (x.ActivityEnabled == false)
                    {
                        x.ActivityEnabled = true;
                        timer.Enabled = true;
                        timer.Start();
                        timer.Elapsed += OnTimedEvent;
                        x.ActivityDuration = x.ActivityDuration.Add(new TimeSpan(0, 0, 0, 0, (int)interval)); //new
                        return;
                    }
                    else
                    {
                        x.ActivityEnabled = false;
                        timer.Enabled = false;
                        timer.Stop();
                        x.ActivityDuration = x.ActivityDuration.Add(new TimeSpan(0, 0, 0, 0, (int)interval)); //new
                        return;
                    }

**3。使用秒表的替代方法 - 确实有效但不会更新 UI 直到点击 **

 foreach (var x in ViewModel.UserActivitiesList)
            {

                if (x.ActivityName == myactivitiesModel.ActivityName)
                {
                    if (x.ActivityEnabled == false)
                    {
                        x.ActivityEnabled = true;
                        //timer.Enabled = true;
                        mystopwatch.Restart();
                        mystopwatch.Start();
                        x.ActivityDuration = mystopwatch.Elapsed + x.ActivityDuration;
                        NotifyPropertyChanged("ActivityDuration");
                        //timer.Elapsed += OnTimedEvent;
                        //x.ActivityDuration = x.ActivityDuration.Add(new TimeSpan(0, 0, 0, 0, (int)interval)); //new
                        return;
                    }
                    else
                    {
                        x.ActivityEnabled = false;
                        //timer.Enabled = false;
                        mystopwatch.Stop();
                        x.ActivityDuration = mystopwatch.Elapsed + x.ActivityDuration;
                        NotifyPropertyChanged("ActivityDuration");
                        //x.ActivityDuration = x.ActivityDuration.Add(new TimeSpan(0, 0, 0, 0, (int)interval)); //new
                        return;
                    }

我认为你把这种方式搞得太复杂了。我会创建一个计时器并做这样的事情

using System.Timers;

...


// 100ms == .1s
double interval = 100;

// CREATE ONE TIMER FOR ALL ACTIVITIES
Timer timer = new Timer(interval);
timer.Elapsed += UpdateTimers;
timer.Start();

...

private void UpdateTimers(object sender, EventArgs a)
{
  // this is psudocode, update for your model
  foreach(var a in Activities)
  {
     // if activity is selected
     if (a.Active) {
       // update the elapsed time
       a.Elapsed = a.Elapsed.Add(new Timespan(0,0,0,0,interval));
     }
  }
}

OP

实施的最终解决方案
public page() 
{
            timer.Start();
            timer.Elapsed += UpdateTimers;
}

        private void UpdateTimers(object sender, EventArgs a)
        {

            foreach (var x in ViewModel.UserActivitiesList)
            {
                if (x.ActivityEnabled)
                {
                    x.ActivityDuration = x.ActivityDuration.Add(new 
                    TimeSpan(0, 0, 0, 0, (int)interval));
                }
            }
        }