I have a CollectionView
that has its ItemsSource
bound to an ObservableCollection
and it works fine. But when I add x:DataType="viewmodels:MyPageViewModel"
in the XAML, it does not show any items, even those items that are initialized in the ViewModel's constructor are not shown in the CollectionView
. It also does not show updated items.
Here's my XAML Code (MyPage.xaml):
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage ...
xmlns:viewmodels="clr-namespace:MyProject.ViewModels"
x:DataType="viewmodels:MyPageViewModel"
x:Class="MyProject.Views.MyPage">
<ContentPage.Content>
<StackLayout>
<CollectionView ItemsSource="{Binding Strings}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding .}" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Button Text="Add More" Command="{Binding AddMoreItemsCommand}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
Here I have specified Binding in the C# Code Behind (MyPage.xaml.cs):
BindingContext = new ViewModels.MyPageViewModel();
Here's my ViewModel (MyPageViewModel.cs):
public class MyPageViewModel : INotifyPropertyChanged
{
public ObservableCollection<string> Strings { get { return strings; } set { strings = value; OnPropertyChanged(nameof(Strings)); } }
ObservableCollection<string> strings;
public MyPageViewModel()
{
Strings = new ObservableCollection<string> { "1", "2", "3" };
}
public ICommand AddMoreItemsCommand => new Command(() =>
{
Strings.Add("4");
Strings.Add("5");
Strings.Add("6");
});
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Note that if I remove x:DataType="viewmodels:MyPageViewModel"
, everything works fine.
Also if I edit something in ColllectionView
while the app is running, it renders the items properly as expected through XAML Hot Reload. But it doesn't fulfil the need as it does not work if I rerun the Project again.
Is there a bug in Xamarin Forms, I am running the latest Xamarin.Forms 5.0.0.2515, I have also tried it in Xamarin.Forms 5.0.0.2478? Or am I missing something? any help would be much appreciated.
CodePudding user response:
Specify x:DataType="modelOfYourCollection"
in <DataTemplate>
of the CollectionView
.
If you are using any control that has a DataTemplate you must also setup the compiled binding on it. Here, we have a CollectionView
that is data bound to an ObservableCollection<string>
. We can bring in the System
namespace just like we did for the viewmodels:MyPageViewModel
because we are using collection of string type and String class resides in System namespace.
- Firstly, add namespace in root of the page:
xmlns:sys="clr-namespace:System;assembly=System.Runtime"
- And then in your
DataTemplate
add:
<DataTemplate x:DataType="sys:String">
If we are using our own Custom Model, add model's namespace at the root of the page and then specify model class in DataTemplate
of the CollectionView
. Note that we have to use Model and not ViewModel in the DataTemplate
.
Rest of the code is correct
Final XAML Code will look like:
<ContentPage ...
xmlns:viewmodels="clr-namespace:MyProject.ViewModels"
xmlns:models="clr-namespace:MyProject.Models"
xmlns:sys="clr-namespace:System;assembly=System.Runtime"
x:DataType="viewmodels:MyPageViewModel"
x:Class="MyProject.Views.MyPage">
...
<CollectionView ItemsSource="{Binding Strings}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="sys:String">
<Label Text="{Binding .}" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<!-- For collection of your custom model -->
<CollectionView ItemsSource="{Binding Monkeys}" >
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:MonkeyModel">
<Label Text="{Binding MonkeyName}" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage>
Why use Compiled Bindings? Compiled bindings are resolved more quickly than classic bindings. Hence, improves data binding performance in Xamarin.Forms applications.