locked
how to make observablecollection to update UI without using MVVM.... RRS feed

  • Question

  • User392605 posted

    i don't want to use MVVM,,please anyone suggest me how to achieve that??? here is my code

    public class ClassInfos { public int Id { get; set; }

        public string ClassName { get; set; }
    }
    

    ///////////////////////////////in main page/////////////////////////

    FirebaseClient firebase = new FirebaseClient("https://url~~~~/");

        ObservableCollection<ClassInfos>listOfClass = new ObservableCollection<ClassInfos>();
          public ClassInfoPage()
          {
            InitializeComponent();
            this.BindingContext = listOfClass;
           }
    
        protected async override void OnAppearing()
        {
            base.OnAppearing();
            try
            {
                           ///getting the list from firebase database/////////////////
    
                var data = (await firebase.Child("Class").OnceAsync<ClassInfos>()).Select(item => new ClassInfos
                {
                    ClassName = item.Object.ClassName,
                    Id = item.Object.Id,
                }).ToList();
    
    
               if(listOfClass != null)
               {
                    listOfClass.Clear();
                    foreach (var item in data)
                    {
                        //////add the data into ObservableCollection<ClassInfos>listOfClass//////////////
                        listOfClass.Add(new ClassInfos
                        {
                            ClassName = item.ClassName,
                            Id = item.Id,
                        });
                    }
    
                }
                ClassList.ItemsSource = listOfClass;
    
    
            }
    

    //////////////////////deleting the item //////////////// private async void DeleteMenuItem_Clicked(object sender, EventArgs e) { var menuitem = sender as MenuItem; var Deletcontent = menuitem.CommandParameter as ClassInfos; var deletefirebase = (await firebase.Child("Class").OnceAsync()).Where(item => item.Object.Id == Deletcontent.Id).FirstOrDefault(); await firebase.Child("Class").Child(deletefirebase.Key).DeleteAsync(); }

    Monday, March 9, 2020 9:38 AM

All replies

  • User392605 posted

    i did but that's not a cool way to do i am just refreshing the page in each delete,,i don't want to do that cause it gives bad effect on UI. so anyone suggest me what to do ??? private async void DeleteMenuItem_Clicked(object sender, EventArgs e) { var menuitem = sender as MenuItem; var Deletcontent = menuitem.CommandParameter as ClassInfos; var deletefirebase = (await firebase.Child("Class").OnceAsync()).Where(item => item.Object.Id == Deletcontent.Id).FirstOrDefault(); await firebase.Child("Class").Child(deletefirebase.Key).DeleteAsync();

    //////////////////refreshing the data //////////////////////// var data = (await firebase.Child("Class").OnceAsync()).Select(item => new ClassInfos { ClassName = item.Object.ClassName, Id = item.Object.Id, }).ToList();

            if (listOfClass != null)
            {
                listOfClass.Clear();
                foreach (var item in data)
                {
    
                    listOfClass.Add(new ClassInfos
                    {
                        ClassName = item.ClassName,
                        Id = item.Id,
                    });
                }
    
            }
        }
    
    Monday, March 9, 2020 9:44 AM
  • User365353 posted

    Xamarin Forms controls are created to use MVVM. So your code for Xamarin Forms never be good without using MVVM. I will show you how to delete items without refreshing whole list with MVVM. First, you need to set the page to it's BindingContext (ideally you need to create other class with data only which called ViewModel and bind this to page's BindingContext).

    this.BindingContext = this;

    Second, in XAML set ItemsSource property through the binding to your list.

    <ListView ItemsSource="{Binding listOfClass}">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <ViewCell>
                                <Button Command="{Binding Source={RelativeSource AncestorType={x:Type YourPage}}, Path=DeleteItemCommand}" CommandParameter="{Binding .}"/>
                            </ViewCell>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
    

    Third, define DeleteItemCommand in your binding context.

    public Command DeleteItemCommand { get; }
    
    public YourPage()
    {
        DeleteItemCommand = new Command(async(object listItem)=>await this.DeleteItemAsync(listItem));
    }
    
    private async void DeleteItemAsync(object item)
            {
                //After deleting item in database delete this item in collection:
                listOfClass.Remove(item);
            }
    

    About bindings: https://docs.microsoft.com/ru-ru/xamarin/xamarin-forms/app-fundamentals/data-binding/relative-bindings#bind-to-an-ancestor https://docs.microsoft.com/ru-ru/xamarin/xamarin-forms/xaml/xaml-basics/data-binding-basics https://docs.microsoft.com/ru-ru/xamarin/xamarin-forms/xaml/xaml-basics/data-bindings-to-mvvm

    Monday, March 9, 2020 4:12 PM
  • User393244 posted

    Rather than clearing and re-populating the list when things change, try doing a smart update of the list.

    // first remove any extra entries no longer needed
    while (listOfClass.Count > data.Count)
    {
       listOfClass.RemoveAt(listOfClass.Count - 1);
    }
    
    for (int i = 0; i < data.Count; i++)
    {
       // if there aren't enough entries, add one for this item
       if (listOfClass.Count <= i)
       {
          var newItem = new ClassInfos();
          newItem.Id = data[i].Id;
          newItem.ClassName = data[i].ClassName;
          listOfClass.Add();
       }
       // there are enough entries, just update this one
       else
       {
          var existingItem = listOfClass[i];
          existingItem.Id = data[i].Id;
          existingItem.ClassName = data[i].ClassName;
       }
    }
    

    This minimizes the changes to the list to only what is needed. However, the above won't work as is. The problem is, ObservableCollection will update the list when you add/remove items. But it will not update the list when you modify existing items (which the example does in the else case in the loop).

    To get that to work, you could make an ObservableClassInfos class which implements INotifyPropertyChanged and have your ObservableCollection use that instead.

    public class ObservableClassInfos : INotifyPropertyChanged
    {
       private int _id;
       public int Id
       {
          get { return _id; }
          set { SetProperty(ref _id, value); }
       }
    
       private string _className;
       public string ClassName
       {
          get { return _className; }
          set { SetProperty(ref _className, value); }
       }
    
            protected bool SetProperty<T>(ref T backingStore, T value,
                [CallerMemberName]string propertyName = "",
                Action onChanged = null)
            {
                if (EqualityComparer<T>.Default.Equals(backingStore, value))
                    return false;
    
                backingStore = value;
                onChanged?.Invoke();
                OnPropertyChanged(propertyName);
                return true;
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }  
    }
    

    If you switch over to using ObservableClassInfos and then use that smart update code then it should work and give you very nice updates. Setting the Id and ClassName on an item already in the list will update in the list and you're only removing adding items when necessary.

    I was stuck with this same exact issue as well and the above worked great. Even with a very high update rate it still looks good.

    Monday, March 16, 2020 4:47 PM