Best way to handle switch control in ViewModel

RobDurranceRobDurrance ✭✭USMember ✭✭
edited May 28 in Xamarin.Forms

Hi there,
I am still quite a novice at the MVVM thing so please bear with me. I have an Observable Collection in a ViewModel that has a bool (property?, item?, member?) that is bound to a switch control inside a ListView. When the switch is toggled on, I want to add that row plus some other data to a local Sqlite Database. When it is toggled off, I want it to delete that entry. I have done this previously in the code behind, but now I want to do it in the ViewModel. From what I have read, It seems like subscribing to the changed event of the collection could be a good way to do it because it already fires when changes occur. In the model that is used to populate the observable collection, there is already an "isSelected" property so I can go through the list and look for the ones that have "isSelected" as true and then insert those into the database. The problem that I am running into is what to do when the toggle is off. Doing it this way will not allow me to find the item because I can no longer search since then they will all be false.
Here is my ViewModel so far. I am sure that some things are probably wrong, I just want to make sure that this will work before I go and clean it up:

 public class exercisesVM: INotifyPropertyChanged
    {
        public exercisesVM(int exID)
        {
            Debug.WriteLine("Value sent to ExVM is: " + exID);
            IRestService service = new RestService();
            Task.Run(async () => ExerciseLst = new ObservableCollection<exercise>(await service.GetExercisesAync(exID)));
            ExerciseLst.CollectionChanged += ExerciseLst_CollectionChanged;
            Debug.WriteLine("ExerciseVM Started");
        }

        private async void ExerciseLst_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {

            Debug.WriteLine("Made it to the Exercise CollectionChanged Event");
            var exerciseSelected = ExerciseLst.Where(x => x.exerciseIsSelected).ToList();
            var exLogTbl = new ExLogTbl();
            foreach (var item in exerciseSelected)
            {
                exLogTbl.exerciseDate = DateTime.Today;
                exLogTbl.exerciseID = item.exerciseID;
                exLogTbl.exerciseUserID = "Me";
                exLogTbl.exerciseName = item.exerciseName;
                exLogTbl.exerciseCalCount = item.excerciseCalCount;
                exLogTbl.isCompleted = false;
            }
           //This is where I save it to the local DB
            await App.Database.SaveExerciseAsync(exLogTbl);

        }
        private ObservableCollection<exercise> _ExerciseLst;
        public ObservableCollection<exercise> ExerciseLst
        {
            get
            {
                Debug.WriteLine("ExVM GET");
                return _ExerciseLst;
            }
            set
            {
                if (value != _ExerciseLst)
                {
                    _ExerciseLst = value;
                    OnPropertyChanged();
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string caller = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(caller));
        }

    }

So, my question is: Should I try to use the property changed event or should I just write a command in the ViewModel (with behaivors) that will handle the switch event? Or, is this one of those times where I should just put it in the code behind because it starts becoming too specific to the page to be used with a ViewModel?
Thank you,
Rob Durrance

Answers

  • LucasZhangLucasZhang Xamurai Member, Xamarin Team Xamurai

    What is the means of **Doing it this way will not allow me to find the item because I can no longer search since then they will all be false. **?

    ExerciseLst.CollectionChanged will only been called when you add or remove items to ItemsSource.Only open(close) will not call it.

  • LucasZhangLucasZhang Xamurai Member, Xamarin Team Xamurai
    edited May 28

    if you want to save or delete item to DB when you tap the switch. Refer the following code

    in your model

    public class Exercise:INotifyPropertyChanged
    {
    
      public event PropertyChangedEventHandler PropertyChanged;
    
      private bool isSelected;
      public bool IsSelected { get { return isSelected; } set { isSelected = value; NotifyPropertyChanged(nameof(IsSelected)); } }
    
      //...
      // other binding property
    
    
      protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
      {
         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
    }
    

    in ViewModel

    public class MyViewModel 
    {       
      public ObservableCollection<Exercise> ExerciseLst { get; set; }
      public ObservableCollection<Exercise> SelectedExerciseLst { get; set; }
    
      public MyViewModel()
      {
         ExerciseLst = new ObservableCollection<Exercise>() {
           new Exercise(){ IsSelected=true },
           new Exercise(){ IsSelected=false },
           new Exercise(){ IsSelected=true },
           new Exercise(){ IsSelected=false },
           new Exercise(){ IsSelected=true },
           new Exercise(){ IsSelected=true },
    
           };
    
         SelectedExerciseLst = new ObservableCollection<Exercise>();
    
          for (int i = 0; i < ExerciseLst.Count; i++)
          {
             Exercise exercise = ExerciseLst[i];
             exercise.PropertyChanged += (sender, e) =>
             {
                if (exercise.IsSelected)
                  {
                      SelectedExerciseLst.Add(exercise);
                  }
               if (i == ExerciseLst.Count - 1)
                 {
                     ExerciseLst_CollectionChanged();
                 }
              };
    
    
      }
    }
    
Sign In or Register to comment.