Janice_Feb_1998
Janice_Feb_1998

Reputation: 23

How can I use a Xamarin DataTemplate with an ObservableCollection instead of a List?

I have a page that looks like this. I tested out the code using a List but I need to use an ObservableCollection as the contents of the data will change after it's initially populated. My problem is that when I change from a List to ObservableCollection I no longer see any data appearing.

    public YourPage()
    {
    
      var viewModel = _vm = new YourPageViewModel()

      var dataTemplate = new DataTemplate(()=>
      {
         var mygrid = new MyGrid ();
         mygrid.SetBinding(MyGrid.TextProperty, "Text");
         return mygrid;
      });
      StackLayout stackLayout = new StackLayout();
      BindableLayout.SetItemsSource(stackLayout, _vm.ListOfText);
      BindableLayout.SetItemTemplate(stackLayout, dataTemplate);
      Content = stackLayout;
   }

   protected override void OnAppearing()
   {
      base.OnAppearing();
     _vm.OnAppearing();
   }

And a ViewModel

  public partial class YourPageViewModel : BaseViewModel
  {
 
     private ObservableCollection<TestModel> _listOfText;

     public ObservableCollection<TestModel> ListOfText{
        get => _listOfText;
        set => SetProperty(ref _listOfText, value);
     }

     public void OnAppearing()
     {
            var tempList = ...;
            ListOfText = new ObservableCollection<TestModel>(tempList);
     }
  }

Given this situation with an ObservableCollection then the data template doesn't seem to show any data.

Does anyone have an idea what might be wrong?

Upvotes: 0

Views: 158

Answers (3)

Janice_Feb_1998
Janice_Feb_1998

Reputation: 23

The solutions given work for when the data is populate one time after the binding is set up but then after that the layout will not be refreshed.

To solve this problem what is needed is to place the DataTemplate in a CollectionView

  CollectionView collectionView = new CollectionView();
  collectionView.SetBinding(ItemsView.ItemsSourceProperty, "ListOfText");
  collectionView.ItemTemplate =  new DataTemplate(() =>
  {
     var mygrid = new MyGrid ();
     mygrid.SetBinding(MyGrid.TextProperty, "Text");
     return mygrid;
  });
  Content = collectionView;

When this is done the ObservableCollection can be refreshed at any time and the screen layout will change when it's refreshed.

Upvotes: 0

Leo Zhu
Leo Zhu

Reputation: 15001

Becasue when you set the data-binding in the constructor of your page,the ListOfText is not populated the data until you call _vm.OnAppearing(); in OnAppearing() method.

You could try to pipulate the data in the constructor of your viewmodel:

public partial class YourPageViewModel : BaseViewModel
{

 private ObservableCollection<TestModel> _listOfText;

 public ObservableCollection<TestModel> ListOfText{
    get => _listOfText;
    set => SetProperty(ref _listOfText, value);
 }
 public YourPageViewModel ()
 {
    var tempList = ...;
    _listOfText = new ObservableCollection<TestModel>(tempList);
 }
}

and then you don't need to call _vm.OnAppearing(); in OnAppearing() method. You need to make sure that you have populated your data when you bind it.

Upvotes: 1

Gerald Versluis
Gerald Versluis

Reputation: 34063

You will want to create the ObservableCollection only once. If you use data-binding on it, it will subscribe to certain events that will emit the changes in the collection.

By doing ListOfText = new ObservableCollection<TestModel>(tempList); it will cause those events to be disconnected and your data won't show up. Instead, change it to be more like this

public partial class YourPageViewModel : BaseViewModel
  {
     // This changed
     private ObservableCollection<TestModel> _listOfText = new ObservableCollection<TestModel>(tempList);

     public ObservableCollection<TestModel> ListOfText{
        get => _listOfText;
        set => SetProperty(ref _listOfText, value);
     }

     public void OnAppearing()
     {
            var tempList = ...;

            // This changed
            ListOfText.Clear();

            foreach (var text in tempList)
                ListOfText.Add(text);
     }
  }

Notice how I only create the ObservableCollection once and repopulate each time instead of creating a new one.

Upvotes: 1

Related Questions