I have a list view in Xamarin Froms Project as :
<ListView x:Name="ExerciseList" HasUnevenRows="False" SeparatorVisibility="None" RowHeight="200">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical">
<StackLayout Orientation="Horizontal" HorizontalOptions="CenterAndExpand">
<Entry Text="{Binding ExerciseName}" HorizontalTextAlignment="Center" Focused="ExerciseName_Focused" HorizontalOptions="CenterAndExpand">
<Entry.GestureRecognizers>
<TapGestureRecognizer Tapped="ExerciseNameGestureRecognizer_Tapped"/>
</Entry.GestureRecognizers>
</Entry>
<Image IsVisible="{Binding GreenVisible}" Source="smallgreenadd.png"/>
<Image IsVisible="{Binding RedVisible}" Source="smallredremove.png"/>
</StackLayout>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Label Text="Sets : " Grid.Column="0" Grid.Row="0" HorizontalTextAlignment="Center" HorizontalOptions="CenterAndExpand" />
<Label Text="Weights : " Grid.Column="0" Grid.Row="1" HorizontalTextAlignment="Center" HorizontalOptions="CenterAndExpand" />
<Label Text="Reps: " Grid.Column="0" Grid.Row="2" HorizontalTextAlignment="Center" HorizontalOptions="CenterAndExpand" />
<Entry Text="{Binding Sets}" Grid.Column="1" Grid.Row="0" HorizontalTextAlignment="Center" HorizontalOptions="CenterAndExpand" />
<Entry Text="{Binding Weights}" Grid.Column="1" Grid.Row="1" HorizontalTextAlignment="Center" HorizontalOptions="CenterAndExpand" />
<Entry Text="{Binding Reps}" Grid.Column="1" Grid.Row="2" HorizontalTextAlignment="Center" HorizontalOptions="CenterAndExpand" />
</Grid>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This is attached to a View Modal called ExerciseViewModal. This is:
public class ExerciseViewModal : BaseViewModal
{
private List<AddExerciseModal> _addExerciseModals;
public List<AddExerciseModal> AddExerciseModals
{
get { return _addExerciseModals; }
set
{
_addExerciseModals = value;
OnPropertyChanged("AddExerciseModals");
}
}
public ExerciseViewModal()
{
_addExerciseModals = new List<AddExerciseModal>();
if (AddExerciseModals.Count == 0)
{
for (int i = 0; i < 7; i++)
{
AddExerciseModal addExerciseModal = new AddExerciseModal
{
ExerciseID = i,
ExerciseName = "Excercise " + i,
GreenVisible = false,
RedVisible = true,
Sets = "2",
Reps = "10",
Weights = "10"
};
AddExerciseModals.Add(addExerciseModal);
}
AddExerciseModals[AddExerciseModals.Count - 1].GreenVisible = true;
AddExerciseModals[AddExerciseModals.Count - 1].RedVisible = false;
}
}
}
AddExerciseModal class :
public class AddExerciseModal
{
public int ExerciseID { get; set; }
public string ExerciseName { get; set; }
public string Weights { get; set; }
public string Reps { get; set; }
public string Sets { get; set; }
public bool GreenVisible { get; set; }
public bool RedVisible { get; set; }
}
Whenever I try to change the sets/reps/Weights property inside the ListView I always get an error saying:
"Collection was modified; enumeration operation may not execute."
How can I solve this?
Can you change your List to ObservableCollection and try it .That will resolve the problem.
Related
I have 2 classes
Terms
public class Terms
{
[PrimaryKey, AutoIncrement]
public int TermId { get; set; }
public string TermName { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
public DateTime RealStart => DateTime.Parse(StartDate);
public DateTime RealEnd => DateTime.Parse(EndDate);
}
Courses
public class Courses
{
[PrimaryKey, AutoIncrement]
public int CourseId { get; set; }
public int TermId { get; set; }
public string CourseName { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
public DateTime RealStart => DateTime.Parse(StartDate);
public DateTime RealEnd => DateTime.Parse(EndDate);
public string CIName { get; set; }
public string CIEmail { get; set; }
public string CIPhone { get; set; }
public string Status { get; set; }
public bool Notifications { get; set; }
public string Notes { get; set; }
}
Term 1 -
Course 1
Course 2
When selecting a course from Term 1, I'm trying to display the expanded course details for that course.
xaml
<CollectionView x:Name="CourseCollection"
ItemsSource="{Binding Courses}"
EmptyView="No Courses to display"
SelectionMode="Single"
SelectionChanged="CourseCollection_SelectionChanged">
C#
private async void CourseCollection_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var course = (Courses)e.CurrentSelection.FirstOrDefault();
if (e.CurrentSelection != null)
{
await Navigation.PushAsync(new CoursesDetail(course));
}
}
It's displaying both courses
CoursesDetail
xaml
<CollectionView x:Name="CoursesCollection"
ItemsSource="{Binding Courses}"
EmptyView="No courses to view"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Grid Padding="5" RowSpacing="1" ColumnSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" FontSize="Medium" VerticalTextAlignment="Center">Course ID</Label>
<Label Text="{Binding CourseId}" Grid.Row="0" Grid.Column="1" FontSize="Medium" x:Name="CourseId" ></Label>
<Label Grid.Row="1" Grid.Column="0" FontSize="Medium" VerticalTextAlignment="Center">Term ID</Label>
<Label Text="{Binding TermId}" Grid.Row="1" Grid.Column="1" FontSize="Medium" x:Name="TermId"></Label>
<Label Grid.Row="2" Grid.Column="0" FontSize="Medium" VerticalTextAlignment="Center">Course Name</Label>
<Label x:Name="CourseName" Grid.Row="2" Grid.Column="1" FontSize="Medium" VerticalTextAlignment="Center" Text="{Binding CourseName}"></Label>
<Label Grid.Row="3" Grid.Column="0" FontSize="Medium" VerticalTextAlignment="Center">Start Date</Label>
<Label Grid.Row="3" Grid.Column="1" FontSize="Medium" x:Name="StartDate" Text="{Binding StartDate}"></Label>
<Label Grid.Row="4" Grid.Column="0" FontSize="Medium" VerticalTextAlignment="Center">End Date</Label>
<Label Grid.Row="4" Grid.Column="1" FontSize="Medium" x:Name="EndDate" Text="{Binding EndDate}"></Label>
<Label Grid.Row="5" Grid.Column="0" FontSize="Medium" VerticalTextAlignment="Center">Instructor Name</Label>
<Label x:Name="CIName" Grid.Row="5" Grid.Column="1" FontSize="Medium" VerticalTextAlignment="Center" Text="{Binding CIName}"></Label>
<Label Grid.Row="6" Grid.Column="0" FontSize="Medium" VerticalTextAlignment="Center">Instructor Email</Label>
<Label x:Name="CIEmail" Grid.Row="6" Grid.Column="1" FontSize="Medium" VerticalTextAlignment="Center" Text="{Binding CIEmail}"></Label>
<Label Grid.Row="7" Grid.Column="0" FontSize="Medium" VerticalTextAlignment="Center">Instructor Phone</Label>
<Label x:Name="CIPhone" Grid.Row="7" Grid.Column="1" FontSize="Medium" VerticalTextAlignment="Center" Text="{Binding CIPhone}"></Label>
<Label Grid.Row="8" Grid.Column="0" FontSize="Medium" VerticalTextAlignment="Center">Course Status</Label>
<Label Grid.Row="8" Grid.Column="1" x:Name="Status" FontSize="Medium" Text="{Binding Status}"></Label>
<Label Grid.Row="9" Grid.Column="0" FontSize="Medium" VerticalTextAlignment="Center">Notes</Label>
<Label x:Name="Notes" Grid.Row="9" Grid.Column="1" FontSize="Medium" Text="{Binding Notes}"></Label>
<Label Grid.Row="10" Grid.Column="0" FontSize="Medium" VerticalTextAlignment="Center">Notifications</Label>
<Label x:Name="Notifications" Grid.Row="10" Grid.Column="1" FontSize="Medium" Text="{Binding Notifications}"></Label>
</Grid>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
c#
public partial class CoursesDetail : ContentPage
{
private readonly int _selectedCourseId;
private Courses theBiggestCourses;
protected override async void OnAppearing()
{
base.OnAppearing();
CoursesCollection.ItemsSource = await database.GetCourses(_selectedCourseId);
AssessmentsCollection.ItemsSource = await database.GetAssessments(_selectedCourseId);
}
public CoursesDetail()
{
InitializeComponent();
}
public CoursesDetail(Courses courses)
{
_selectedCourseId = courses.CourseId;
InitializeComponent();
this.theBiggestCourses = courses;
}
I've tried manually passing through each text field through the constructor. I have sample data that should auto populate and thought that it was the issue, but I removed those methods and tried manually added a Term, Courses for that Term but as soon as it gets to more than 1 course, it wacks out.
EDIT - My pea sized brain theory could be that since Terms is getting passed through as an object, capturing all the elements of that object, that it's still holding onto that Term object, so when calling the Courses object, it's capturing all the courses objects for that terms object. I hope I explained that decent.
EDIT2 - GET COURSES
public static async Task<IEnumerable<Courses>> GetCourses(int termId)
{
await Init();
var courses = await db.Table<Courses>()
.Where(i => i.TermId == termId).ToListAsync();
return courses;
}
public static async Task<IEnumerable<Courses>> GetCourses()
{
await Init();
var courses = await db.Table<Courses>().ToListAsync();
return courses;
}
These are the two for GetCourses. Is it because we're passing through an int termId here and an object in the method through the constructor? Then it defaults to the unparameterized constructor, which is going to return all of them?
GetCourses expects a TermID
public static async Task<IEnumerable<Courses>> GetCourses(int termId)
{
await Init();
var courses = await db.Table<Courses>()
.Where(i => i.TermId == termId).ToListAsync();
return courses;
}
but when you call it you are passing a CourseID
CoursesCollection.ItemsSource = await database.GetCourses(_selectedCourseId);
I have a chat application that have a list of chat members which should change property Lida/BgFrame when the last message is seen. Adding new elements to this list works fine, but changing properties of existing elements do nothing.
See my code below(relevant parts only, I have omitted a lot of irrelevant code for this question):
namespace MasterDetailPageNavigation.XAML
{
public static ObservableCollection<ChatMembers> Lista { get; set; } = new ObservableCollection<ChatMembers>();
public static ReaderWriterLockSlim valuesLock = new ReaderWriterLockSlim();
void ObservableCollectionCallback(IEnumerable collection, object context, Action accessMethod, bool writeAccess)
{
var collectionLock = (ReaderWriterLockSlim)context;
Action enterLock = writeAccess ? new Action(collectionLock.EnterWriteLock) : new Action(collectionLock.EnterReadLock);
Action exitLock = writeAccess ? new Action(collectionLock.ExitWriteLock) : new Action(collectionLock.ExitReadLock);
enterLock();
try { accessMethod(); } finally { exitLock(); }
}
public class ChatMembers : INotifyPropertyChanged // THIS IS THE BINDABLE OBJECT
{
public Color WhiteAlpha = new Color(255, 255, 255, 0.7);
public Color GreenAlpha = new Color(160.0f / 255.0f, 255.0f / 255.0f, 160.0f / 255.0f, 0.2);
private Guid _talk { get; set; }
public Guid talk
{
get { return _talk; }
set
{
_talk = value;
NotifyPropertyChanged("talk");
}
}
private string _Username { get; set; }
public string Username
{
get { return _Username; }
set
{
_Username = value;
this.NotifyPropertyChanged("Username");
}
}
private bool _Lida { get; set; }
public bool Lida
{
get { return _Lida; }
set
{
_Lida = Convert.ToBoolean(value);
FrameBg = !_Lida ? (UserFrom == MainPage.MeuID ? WhiteAlpha : GreenAlpha) : WhiteAlpha;
this.NotifyPropertyChanged("Lida");
}
}
private Color _FrameBg { get; set; }
public Color FrameBg
{
get { return _FrameBg; }
set
{
_FrameBg = value;
this.NotifyPropertyChanged("FrameBg");
}
}
private string _Msg { get; set; }
public string Msg
{
get { return _Msg; }
set
{
_Msg = value;
this.NotifyPropertyChanged("Msg");
}
}
public event PropertyChangedEventHandler PropertyChanged;
void NotifyPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
// Code that updates property "Lida":
tasks.Add(Task.Run(() =>
{
Color GreenAlpha = new Color(160.0f / 255.0f, 255.0f / 255.0f, 160.0f / 255.0f, 0.2);
bool itemExists = false;
valuesLock.EnterReadLock();
try
{
itemExists = Lista.Any(i => i.talk == guid);
}
finally { valuesLock.ExitReadLock(); }
if (itemExists)
{
ChatMembers item;
int indexof;
valuesLock.EnterReadLock();
try
{
item = Lista.Single(i => i.talk == guid);
indexof = Lista.IndexOf(item);
}
finally { valuesLock.ExitReadLock(); }
_ = Device.InvokeOnMainThreadAsync(() =>
{
valuesLock.EnterWriteLock();
try
{
Lista[indexof].Lida = true;
Lista[indexof].FrameBg = new Color(255, 255, 255, 0.7); //desperate try but no success
}
finally { valuesLock.ExitWriteLock(); }
});
}
}));
}
VIEW CODE BEHIND(relevant part):
CollectionViewMembers.BindingContext = MainPage.Lista;
VIEW XAML(relevant part):
<CollectionView x:Name="CollectionViewMembers" SelectionMode="None"
HorizontalScrollBarVisibility="Never" ItemsSource="{Binding .}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="6,10,5,1" Margin="0,0,0,0" BackgroundColor="{Binding FrameBg}">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Evento}" />
</StackLayout.GestureRecognizers>
<Grid HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions>
<Frame IsClippedToBounds="True" Grid.Row="0" Grid.Column="0" CornerRadius="30" Padding="0" Margin="0">
<ffimageloading:CachedImage DownsampleToViewSize="True" HeightRequest="100" IsOpaque="True" Source="{Binding Imagem}" Aspect="AspectFill" LoadingPlaceholder="resource://MasterDetailPageNavigation.shared.icon_default.png" ErrorPlaceholder="resource://MasterDetailPageNavigation.shared.icon_default.png" />
</Frame>
<Grid Grid.Row="0" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="15" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="20" />
<RowDefinition Height="15" />
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" Text="" TextColor="{Binding ColorOnline}" HorizontalOptions="Center" VerticalOptions="Center" FontSize="15">
<Label.FontFamily>
<OnPlatform x:TypeArguments="x:String" Android="Font-Awesome-Free-Solid.otf#FontAwesome5Free-Solid" iOS="FontAwesome5Free-Solid" />
</Label.FontFamily>
</Label>
<Label Grid.Column="1" Grid.Row="0" Text="{Binding Username}" HorizontalOptions="StartAndExpand" VerticalOptions="Center" FontSize="18" FontAttributes="Bold" LineBreakMode="TailTruncation" />
<Label Grid.ColumnSpan="2" Grid.Column="0" Grid.Row="1" Text="{Binding Msg}" FontSize="15" HorizontalOptions="StartAndExpand" VerticalOptions="Start" LineBreakMode="TailTruncation" />
<Label Grid.ColumnSpan="1" Grid.Column="1" Grid.Row="2" Text="{Binding DataHora}" FontSize="11" TextColor="#CACACA" HorizontalOptions="End" VerticalOptions="Start" />
</Grid>
</Grid>
<BoxView Margin="0,10,0,0" HeightRequest="0.05" WidthRequest="100" BackgroundColor="#CCE5E5E5"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
I also tried to do Lista[indexOf]=item; but no UI update.
Where is my mistake?
I am trying to set the ItemsSource of a ListView from a nested ObservableCollection List.
While HeaderGroups are being created, Items in the groups are empty. Any idea?
Here is my code:
Classes:
public class TableDataGroup
{
public TableDataGroup(String imagepath, String championship, String tip)//, Color headergroupbgcolor,)
{
this.ImagePath = imagepath;
this.Championship = championship;
this.Tip = tip;
this.Items = new ObservableCollection<TableDataItem>();
}
public string ImagePath { get; private set; }
public string Championship { get; private set; }
public string Tip { get; private set; }
public ObservableCollection<TableDataItem> Items { get; set; }
}
public class TableDataItem
{
public TableDataItem(String imagepath, Color backgroundTipColour, String time, String teamone...)
{
this.ImagePath = imagepath;
this.BackgroundTipColour = backgroundTipColour;
this.Time = time;
this.TeamOne = teamone;
//...
}
public string ImagePath { get; private set; }
public Color BackgroundTipColour { get; private set; }
public string Time { get; private set; }
public string TeamOne { get; private set; }
//...
}
Calls:
mainPageLoadViewModel.tableDataGroup = new ObservableCollection<TableDataGroup>();
for (int i = 0; i < 10; i++)
{
TableDataGroup tableDataGroup = new TableDataGroup("value", "value", "value","TIP");
for (int x = 0; x < 10; x++)
{
tableDataGroup.Items.Add(new TableDataItem("flag",
backgroundtipcolor,
time,
teamone,
//...));
}
mainPageLoadViewModel.tableDataGroup.Add(tableDataGroup);
}
ItemsCollectionView.ItemsSource = mainPageLoadViewModel.tableDataGroup; ===> ObservableCollection<TableDataGroup>
xaml:
<ListView x:Name="ItemsCollectionView" ItemsSource="{Binding TableDataGroup}"
IsGroupingEnabled="true" HasUnevenRows="True">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout BackgroundColor="DarkSlateGray" Orientation="Horizontal">
<StackLayout Padding="2" VerticalOptions="CenterAndExpand">
<Image Source="{Binding ImagePath}" HeightRequest="15" WidthRequest="15"/>
</StackLayout>
<StackLayout Padding="2" VerticalOptions="CenterAndExpand">
<Label Text="{Binding Championship}" FontSize="15" TextColor="White"/>
</StackLayout>
<StackLayout Margin="0,0,10,0" VerticalOptions="CenterAndExpand" HorizontalOptions="EndAndExpand">
<Label Text="TIP" FontSize="15" TextColor="White"/>
</StackLayout>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid Padding="10,5,5,10" BackgroundColor="Gray">
<Grid.RowDefinitions>
<RowDefinition Height="25" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="35"/>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="45"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding Time}" Grid.Column="0" FontSize="13" TextColor="Black" VerticalTextAlignment="Center" HorizontalOptions="StartAndExpand"></Label>
<Label Text="{Binding TeamOne}" FontSize="13" TextColor="Black" Grid.Column="1" VerticalTextAlignment="Center" HorizontalOptions="End"></Label>
<Label Text="{Binding ScoreTeamOne}" FontSize="13" Grid.Column="2" BackgroundColor="Gray" TextColor="White" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" WidthRequest="25" MinimumWidthRequest="25"></Label>
<Label Text="{Binding ScoreTeamTwo}" FontSize="13" Grid.Column="3" BackgroundColor="Gray" TextColor="White" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" WidthRequest="25" MinimumWidthRequest="25"></Label>
<Label Text="{Binding TeamTwo}" FontSize="13" TextColor="Black" Grid.Column="4" VerticalTextAlignment="Center"></Label>
<Label Text="{Binding Tip}" FontSize="13" TextColor="White" Grid.Column="5" BackgroundColor="DarkSlateGray" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" HorizontalOptions="Fill"></Label>
</Grid>
</ViewCell.View>
</ViewCell>
<!--<TextCell Text="{Binding Name}" Detail="{Binding Description}"></TextCell>-->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
From this example:
https://blog.verslu.is/stackoverflow-answers/alternate-row-color-listview/
How can I implement it with a grouped listview? I want to have the alternate row color inside every group of the listview, I already tried to implement it with the grouped Listview, but is always giving me "System.InvalidCastException: Specified cast is not valid." inside the DataTemplateSelector.
Listview Code:
<DataTemplate x:Key="evenTemplate">
<ViewCell>
<customRenders:GridConf Margin="0,0,0,0" HorizontalOptions="FillAndExpand" ColumnSpacing="0" RowSpacing="0" ConfigurationItem ="{Binding .}">
<customRenders:GridConf.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="*"/>
</customRenders:GridConf.ColumnDefinitions>
<customRenders:GridConf.RowDefinitions>
<RowDefinition Height="*"/>
</customRenders:GridConf.RowDefinitions>
<BoxView VerticalOptions="CenterAndExpand" HeightRequest="50" Grid.ColumnSpan="1" Margin="-30,0,0,0" Grid.Column="1" HorizontalOptions="FillAndExpand" BackgroundColor="LightGray"/>
<Label VerticalOptions="CenterAndExpand" Margin="10,0,0,0" Grid.Column="1" VerticalTextAlignment="Center" HorizontalOptions="StartAndExpand" Text="tetetetetetet"></Label>
<Image Grid.Column="1" Source="HidePass.png" HeightRequest="30" VerticalOptions="CenterAndExpand" HorizontalOptions="End">
<Image.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" ></TapGestureRecognizer>
</Image.GestureRecognizers>
</Image>
<customRenders:CachedImageItem Grid.Column="0" ConfigurationItem ="{Binding .}" HorizontalOptions="Start" HeightRequest="80" VerticalOptions="Center" x:Name="Image2" Source="{Binding Img}"/>
<customRenders:GridConf.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" ></TapGestureRecognizer>
</customRenders:GridConf.GestureRecognizers>
</customRenders:GridConf>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="unevenTemplate">
<ViewCell>
<customRenders:GridConf Margin="20,0,0,0" HorizontalOptions="FillAndExpand" ColumnSpacing="0" RowSpacing="0" ConfigurationItem ="{Binding .}">
<customRenders:GridConf.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="*"/>
</customRenders:GridConf.ColumnDefinitions>
<customRenders:GridConf.RowDefinitions>
<RowDefinition Height="*"/>
</customRenders:GridConf.RowDefinitions>
<BoxView VerticalOptions="CenterAndExpand" HeightRequest="50" Grid.ColumnSpan="1" Margin="-30,0,0,0" Grid.Column="1" HorizontalOptions="FillAndExpand" BackgroundColor="LightGray"/>
<Label VerticalOptions="CenterAndExpand" Margin="10,0,0,0" Grid.Column="1" VerticalTextAlignment="Center" HorizontalOptions="StartAndExpand" Text="teteteteteette"></Label>
<Image Grid.Column="1" Source="HidePass.png" HeightRequest="30" VerticalOptions="CenterAndExpand" HorizontalOptions="End">
<Image.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" ></TapGestureRecognizer>
</Image.GestureRecognizers>
</Image>
<customRenders:CachedImageItem Grid.Column="0" ConfigurationItem ="{Binding .}" HorizontalOptions="Start" HeightRequest="80" VerticalOptions="Center" x:Name="Image2" Source="{Binding Img}"/>
<customRenders:GridConf.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" ></TapGestureRecognizer>
</customRenders:GridConf.GestureRecognizers>
</customRenders:GridConf>
</ViewCell>
</DataTemplate>
<customRenders1:AlternateColorDataTemplateSelector2 x:Key="alternateColorDataTemplateSelector"
EvenTemplate="{StaticResource evenTemplate}"
UnevenTemplate="{StaticResource unevenTemplate}" />
</ResourceDictionary>
</ContentPage.Resources>
<ListView x:Name="lst" IsGroupingEnabled="True" ItemTemplate="{StaticResource alternateColorDataTemplateSelector}" ItemsSource="{Binding Item}" Margin="5,5,0,0" HasUnevenRows="True" SeparatorVisibility="None">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<customRenders:NativeCell>
<customRenders:NativeCell.View>
<ContentView Padding="10,0,0,0">
<StackLayout>
<Label Text="{Binding Key.Category}" VerticalOptions="Center"/>
</StackLayout>
<ContentView.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={x:Reference ProtocolosPage}, Path=BindingContext.HeaderSelectedCommand}" CommandParameter="{Binding .}"/>
</ContentView.GestureRecognizers>
</ContentView>
</customRenders:NativeCell.View>
</customRenders:NativeCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
</ListView>
AlternateColorDataTemplateSelector:
public DataTemplate EvenTemplate { get; set; }
public DataTemplate UnevenTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
// TODO: Maybe some more error handling here
return ((List<Product>)((ListView)container).ItemsSource).IndexOf(item as Product) % 2 == 0 ? EvenTemplate : UnevenTemplate;
}
ViewModel
public class ProductsViewModel: BindableBase
{
public class SelectCategoryViewModel
{
public string Category { get; set; }
public bool Selected { get; set; }
}
private ObservableCollection<Grouping<string, Product>> _ProductsGrouped;
public ObservableCollection<Product> Productitems { get; set; }
public ObservableCollection<Grouping<string, Models.Product>> ProductsGrouped
{
get
{
return _ProductsGrouped;
}
set
{
_ProductsGrouped = value;
OnPropertyChanged();
}
}
public ObservableCollection<Grouping<SelectCategoryViewModel, Product>> Item { get; set; }
public DelegateCommand<Grouping<SelectCategoryViewModel, Product>> HeaderSelectedCommand
{
get
{
return new DelegateCommand<Grouping<SelectCategoryViewModel, Product>>(g =>
{
if (g == null) return;
g.Key.Selected = !g.Key.Selected;
if (g.Key.Selected)
{
Productitems.Where(i => (i.Category.Equals(g.Key.Category)))
.ForEach(g.Add);
}
else
{
g.Clear();
}
});
}
}
public ProductsViewModel()
{
Productitems = new ObservableCollection<Product>
{
new Product
{
Img = "dss.png",
Url = "Teste",
Category = "service",
Title = "sdsadsadsdsdsa"
},
new Product
{
Img = "dss.png",
Url = "Teste3",
Category = "service",
Title = "sdsadsadsdsdsatest2"
},
new Product
{
Img = "dss.png",
Url = "Teste2",
Category = "Farmacy",
Title = "sdsadsadsdsdsaes"
},
new Product
{
Img = "dss.png",
Url = "Teste4",
Category = "Farmacy",
Title = "sdsadsadsdsdsaF"
},
new Product
{
Img = "dss.png",
Url = "Teste7",
Category = "Farmacy",
Title = "sdsadsadsdsdsaFarmarcia2"
},
new Product
{
Img = "dss.png",
Url = "Teste9",
Category = "Farmacy",
Title = "sdsadsadsdsdsae"
}
};
Item = new ObservableCollection<Grouping<SelectCategoryViewModel, Product>>();
var selectCategories =
Productitems.Select(x => new SelectCategoryViewModel { Category = x.Category, Selected = false })
.GroupBy(sc => new { sc.Category })
.Select(g => g.First())
.ToList();
selectCategories.ForEach(sc => Item.Add(new Grouping<SelectCategoryViewModel, Product>(sc, new List<Product>())));
}
}
This is not working, since the code in the AlternateColorDataTemplateSelector is casting the ItemSource to a List. When you're using grouping, it cannot be a simple list.
On the other hand, when you do an IndexOf on one group, you will receive the index within that group, which does not need to correspond to the index in the full list.
Find a sample repository here: https://github.com/jfversluis/GroupedListViewAlternateRowColor.
In the adapted DataTemplateSelector I flatten out the whole list and get the index from there. Here is the code:
public class AlternateColorDataTemplateSelector : DataTemplateSelector
{
public DataTemplate EvenTemplate { get; set; }
public DataTemplate UnevenTemplate { get; set; }
private List<string> flatList;
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
if (flatList == null)
{
var groupedList = (ObservableCollection<Grouping<string, string>>)((ListView)container).ItemsSource;
flatList = groupedList.SelectMany(group => group).ToList();
}
return flatList.IndexOf(item as string) % 2 == 0 ? EvenTemplate : UnevenTemplate;
}
}
As an optimization, I just create the flat list once. This could go wrong whenever the list is updated with new items. I didn't test that.
The result looks like this:
I have tried to put a ListView inside a CarouselView, but the element binding does not work.
If I comment out the ListView, the project will work fine.
The error is
Binding: 'Contenido' property not found on
'App.ViewModels.FeedListViewModel', target property:
'Xamarin.Forms.ListView.ItemsSource'
The code is as follows:
VIEWMODEL
public class Feed
{
public int IdFeed { get; set; }
public String Title { get; set; }
public bool HasNewElements { set; get; }
public ObservableCollection<NewsFeedDocument> Contenido { get; set; }
}
public class FeedListViewModel : MenuViewModel
{
public ObservableCollection<Feed> Feeds { get; set; }
public FeedListViewModel()
{
Feeds = new ObservableCollection<Feed>();
for (int i = 0; i <= 12; i++)
{
//Creamos lista de elementos Feed
NewsFeedDocument documento = new NewsFeedDocument();
documento.Titulo = "TITULO dasd dsa dsa dsa dsa";
ObservableCollection<NewsFeedDocument> ElementsX = new ObservableCollection<NewsFeedDocument>();
ElementsX.Add(documento);
Feeds.Add(new Feed
{
IdFeed = i ,Title = "SECTOR" + i,
Contenido = ElementsX
});
}
Position = 0;
}
private int _position = 0;
public int Position
{
get { return _position; }
set { _position = value; RaisePropertyChanged(() => Position); }
}
}
}
XAML
<cv:CarouselView x:Name="FeedsItemsCarousel" Grid.Row="2" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
Position="{Binding Position, Mode=TwoWay}"
ItemsSource="{Binding Feeds}">
<cv:CarouselView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!--<Image Grid.RowSpan="2" Aspect="AspectFill" Source="{Binding ImageUrl}"/>-->
<StackLayout Grid.Row="1" BackgroundColor="#80000000" Padding="12">
<Label TextColor="White" Text="{Binding Title}" FontSize="16" HorizontalOptions="Center" VerticalOptions="CenterAndExpand"/>
</StackLayout>
</Grid>
<StackLayout>
<ListView x:Name="FeedListItem" ItemsSource="{Binding Contenido}" RowHeight="120">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" VerticalOptions="FillAndExpand" HorizontalOptions="Fill" BackgroundColor="White" Padding="10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Label Text="{Binding Titulo}" Style="{StaticResource TituloL}" Grid.Row="0" Grid.Column="0" />
</Grid>
<StackLayout Orientation="Horizontal">
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</DataTemplate>
</cv:CarouselView.ItemTemplate>