Alternate row color GroupedListview - c#

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:

Related

Why this Xamarin CollectionView doesn't update UI when changing element property?

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?

Binding property not found / some data displayed some not

I am having issues with displaying data, I can see my data FieldValue and FieldDescriptor in the List property however I still see in output that:
Binding: 'Results' property not found on 'ViewModel.ResultPageViewModel', target property: 'Xamarin.Forms.ListView.ItemsSource'
I can't see any data FieldVisualData in the horizontal list view even thought I can see them in the view model adding to detail and the command also can't be found.
Binding: 'EditTextCommand' property not found on 'Model.DocumentData', target property: 'Xamarin.Forms.TapGestureRecognizer.Command'
Maybe you see something that I am missing?
<StackLayout Spacing="0">
<!--Pictures-->
<StackLayout VerticalOptions="Start" Spacing="0" >
<controls:HorizontalScrollList VerticalOptions="Start" HeightRequest="300" x:Name="carouselView" ItemsSource="{Binding Results, Mode=TwoWay}">
<controls:HorizontalScrollList.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Results.FieldVisualData}"
Margin="5">
<!--<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding HandlePreviewTapped, Source={x:Reference vm}}"
CommandParameter="{Binding}"/>
</Image.GestureRecognizers>-->
</Image>
</DataTemplate>
</controls:HorizontalScrollList.ItemTemplate>
</controls:HorizontalScrollList>
</StackLayout>
<StackLayout VerticalOptions="Start" BackgroundColor="{DynamicResource SeparatorLineColor}" Spacing="10">
<!--DocumentData-->
<Label Grid.Row="0" HorizontalOptions="CenterAndExpand" Text="Občanský průkaz" VerticalOptions="End" ></Label>
<StackLayout BackgroundColor="{DynamicResource PageBackgroundColor}" VerticalOptions="FillAndExpand">
<ListView x:Name="list" BackgroundColor="{DynamicResource PageBackgroundColor}"
HasUnevenRows="True"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
VerticalScrollBarVisibility="Never"
CachingStrategy="RecycleElement"
ItemsSource="{Binding Results, Mode=TwoWay}"
SeparatorVisibility="Default"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid BackgroundColor="{DynamicResource PageBackgroundColor}" Padding="10" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="15*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="12*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="1" Padding="0" Text ="{Binding FieldDescriptor}" Style="{StaticResource SubLabelBlackStyle}" HorizontalOptions="Start" BackgroundColor="{DynamicResource PageBackgroundColor}" HorizontalTextAlignment="Start"/>
<Label Grid.Column="3" Padding="0" Text="{Binding FieldValue}" FontSize="Small" TextColor="#6781a3" BackgroundColor="{DynamicResource PageBackgroundColor}" HorizontalOptions="Start" HorizontalTextAlignment="Start">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding EditTextCommand}" CommandParameter="{Binding FieldValue}" />
</Label.GestureRecognizers>
</Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</StackLayout>
public partial class ResultPage : ContentPage
{
public ResultPage(IEnumerable<DocumentData> data)
{
InitializeComponent();
BindingContext = new ResultPageViewModel(data);
//carouselView.ItemsSource = data;
// list.ItemsSource = data;
}
}
public class ResultPageViewModel : BaseViewModel
{
public ObservableCollection<DocumentData> Results { get; } = new ObservableCollection<DocumentData>();
public ICommand EditTextCommand { get; }
object param = "";
public ResultPageViewModel(IEnumerable<DocumentData> data)
{
EditTextCommand = new Command(async () => await EditTextAsync(param));
Load(data);
}
public void Load(IEnumerable<DocumentData> data)
{
foreach (var result in data)
{
var detail = new DocumentData()
{
FieldVisualData = result.FieldVisualData,
FieldDescriptor = result.FieldDescriptor,
FieldValue = result.FieldValue,
};
Results.Add(detail);
}
}
public async Task EditTextAsync(object param)
{
PromptResult pResult = await UserDialogs.Instance.PromptAsync(new PromptConfig
{
InputType = InputType.Password,
Text = param.ToString(),
Title = Resources.AppResources.Password_lbl,
});
}
}
public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create(
"ItemTemplate",
typeof(DataTemplate),
typeof(HorizontalScrollList),
null,
propertyChanged: (bindable, value, newValue) => ((HorizontalScrollList)bindable).Populate());
public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(
"ItemsSource",
typeof(IEnumerable),
typeof(HorizontalScrollList),
null,
BindingMode.OneWay,
propertyChanged: (bindable, value, newValue) =>
{
var obs = value as INotifyCollectionChanged;
var self = (HorizontalScrollList)bindable;
if (obs != null)
obs.CollectionChanged -= self.HandleItemChanged;
self.Populate();
obs = newValue as INotifyCollectionChanged;
if (obs != null)
obs.CollectionChanged += self.HandleItemChanged;
});
public IEnumerable ItemsSource
{
get => (IEnumerable)this.GetValue(ItemsSourceProperty);
set => this.SetValue(ItemsSourceProperty, value);
}
public DataTemplate ItemTemplate
{
get => (DataTemplate)this.GetValue(ItemTemplateProperty);
set => this.SetValue(ItemTemplateProperty, value);
}
private bool willUpdate = true;
private void HandleItemChanged(object sender, NotifyCollectionChangedEventArgs eventArgs)
{
if (!willUpdate)
{
willUpdate = true;
Device.BeginInvokeOnMainThread(Populate);
}
}
public HorizontalScrollList()
{
this.Orientation = ScrollOrientation.Horizontal;
}
private void Populate()
{
willUpdate = false;
Content = null;
if (ItemsSource == null || ItemTemplate == null)
{
return;
}
var list = new StackLayout { Orientation = StackOrientation.Horizontal };
foreach (var viewModel in ItemsSource)
{
var content = ItemTemplate.CreateContent();
if (!(content is View) && !(content is ViewCell))
{
throw new Exception($"Invalid visual object {nameof(content)}");
}
var view = content is View ? content as View : ((ViewCell)content).View;
view.BindingContext = viewModel;
list.Children.Add(view);
}
if (list.Children.Count == 0)
{
list.Padding = 20;
list.Children.Add(new Label
{
WidthRequest = (list as VisualElement).Width - 30,
HorizontalOptions = new LayoutOptions(LayoutAlignment.Fill, true),
VerticalOptions = new LayoutOptions(LayoutAlignment.Fill, true),
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
FontSize = 15,
});
}
Content = list;
}
Do you want to acheve the result like following GIF?
I do not which style or backgroundcolor that you setted, I set it with static background color.
Here is my editted layout.controls:HorizontalScrollList is a picture, so I comment it.
I change the Command in the TapGestureRecognizer
<StackLayout Spacing="0">
<!--Pictures-->
<StackLayout VerticalOptions="Start" Spacing="0" >
<!--<controls:HorizontalScrollList VerticalOptions="Start" HeightRequest="300" x:Name="carouselView" ItemsSource="{Binding Results, Mode=TwoWay}">
<controls:HorizontalScrollList.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Results.FieldVisualData}"
Margin="5">
--><!--<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding HandlePreviewTapped, Source={x:Reference vm}}"
CommandParameter="{Binding}"/>
</Image.GestureRecognizers>--><!--
</Image>
</DataTemplate>
</controls:HorizontalScrollList.ItemTemplate>
</controls:HorizontalScrollList>-->
</StackLayout>
<StackLayout VerticalOptions="Start" BackgroundColor="White" Spacing="10">
<!--DocumentData-->
<Label Grid.Row="0" HorizontalOptions="CenterAndExpand" Text="Občanský průkaz" VerticalOptions="End" ></Label>
<StackLayout BackgroundColor="Green" VerticalOptions="FillAndExpand">
<ListView x:Name="list" BackgroundColor="Red"
HasUnevenRows="True"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
VerticalScrollBarVisibility="Never"
CachingStrategy="RecycleElement"
ItemsSource="{Binding Results, Mode=TwoWay}"
SeparatorVisibility="Default"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid BackgroundColor="Beige" Padding="10" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="15*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="12*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="1" Padding="0" Text ="{Binding FieldDescriptor}" HorizontalOptions="Start" BackgroundColor="Gray" HorizontalTextAlignment="Start"/>
<Label Grid.Column="3" Padding="0" Text="{Binding FieldValue}" FontSize="Small" TextColor="#6781a3" BackgroundColor="AliceBlue" HorizontalOptions="Start" HorizontalTextAlignment="Start">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding BindingContext.EditTextCommand, Source={x:Reference Name=list}}"
CommandParameter="{Binding .}"
/>
</Label.GestureRecognizers>
</Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</StackLayout>
Here is layout background code. I add three data to make a test.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
IEnumerable<DocumentData> data = new DocumentData[] { new DocumentData() { FieldDescriptor="test 1", FieldValue=1, FieldVisualData=1 } };
data = data.Append(new DocumentData() { FieldDescriptor = "test 2", FieldValue = 2, FieldVisualData = 2 });
data = data.Append(new DocumentData() { FieldDescriptor = "test 3", FieldValue = 3, FieldVisualData = 3 });
this.BindingContext = new ResultPageViewModel(data);
}
}
Here is ResultPageViewModels code.
using Acr.UserDialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
namespace XFormsListviewMvvm
{
public class ResultPageViewModel : BaseViewModel
{
public ObservableCollection<DocumentData> Results { get; } = new ObservableCollection<DocumentData>();
public ICommand EditTextCommand { get; }
object param = "";
public ResultPageViewModel(IEnumerable<DocumentData> data)
{
EditTextCommand = new Command<DocumentData>(async (key) => await EditTextAsync(key));
Load(data);
}
public void Load(IEnumerable<DocumentData> data)
{
foreach (var result in data)
{
var detail = new DocumentData()
{
FieldVisualData = result.FieldVisualData,
FieldDescriptor = result.FieldDescriptor,
FieldValue = result.FieldValue,
};
Results.Add(detail);
}
}
public async Task EditTextAsync(DocumentData param)
{
PromptResult pResult = await UserDialogs.Instance.PromptAsync(new PromptConfig
{
InputType = InputType.Password,
Text = param.FieldValue.ToString(),
Title = "Insert your Password",
});
if (pResult.Ok)
{
param.FieldValue = pResult.Text;
}
}
}
}
If you need to change the value, then layout will display it. you need to implement the BaseViewModel in the DocumentData.
namespace XFormsListviewMvvm
{
public class DocumentData:BaseViewModel
{
private object fieldVisualData = "Hello world";
public object FieldVisualData
{
get => fieldVisualData;
set => SetValue(ref fieldVisualData, value);
}
private object fieldValue = "Hello world";
public object FieldValue
{
get => fieldValue;
set => SetValue(ref fieldValue, value);
}
public object FieldDescriptor { get; internal set; }
}
}
=============Update===================
I add your controls:HorizontalScrollList code. And I change the from <Image Source="{Binding Results.FieldVisualData}"> to <Image Source="{Binding FieldVisualData}" >
Here is running gif.Image could be seen normally.
Here is editted layout.
<StackLayout Spacing="0">
<!--Pictures-->
<StackLayout VerticalOptions="Start" Spacing="0" >
<controls:HorizontalScrollList VerticalOptions="Start" HeightRequest="300" x:Name="carouselView" ItemsSource="{Binding Results, Mode=TwoWay}">
<controls:HorizontalScrollList.ItemTemplate>
<DataTemplate>
<Image Source="{Binding FieldVisualData}"
Margin="5">
<!--<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding HandlePreviewTapped, Source={x:Reference vm}}"
CommandParameter="{Binding}"/>
</Image.GestureRecognizers>-->
</Image>
</DataTemplate>
</controls:HorizontalScrollList.ItemTemplate>
</controls:HorizontalScrollList>
</StackLayout>
<StackLayout VerticalOptions="Start" BackgroundColor="White" Spacing="10">
<!--DocumentData-->
<Label Grid.Row="0" HorizontalOptions="CenterAndExpand" Text="Občanský průkaz" VerticalOptions="End" ></Label>
<StackLayout BackgroundColor="Green" VerticalOptions="FillAndExpand">
<ListView x:Name="list" BackgroundColor="Red"
HasUnevenRows="True"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
VerticalScrollBarVisibility="Never"
CachingStrategy="RecycleElement"
ItemsSource="{Binding Results, Mode=TwoWay}"
SeparatorVisibility="Default"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid BackgroundColor="Beige" Padding="10" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="15*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="12*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="1" Padding="0" Text ="{Binding FieldDescriptor}" HorizontalOptions="Start" BackgroundColor="Gray" HorizontalTextAlignment="Start"/>
<Label Grid.Column="3" Padding="0" Text="{Binding FieldValue}" FontSize="Small" TextColor="#6781a3" BackgroundColor="AliceBlue" HorizontalOptions="Start" HorizontalTextAlignment="Start">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding BindingContext.EditTextCommand, Source={x:Reference Name=list}}"
CommandParameter="{Binding .}"
/>
</Label.GestureRecognizers>
</Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</StackLayout>
Here is layout background code.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
IEnumerable<DocumentData> data = new DocumentData[] { new DocumentData() { FieldDescriptor="test 1", FieldValue=1, FieldVisualData= "https://aka.ms/campus.jpg" } };
data = data.Append(new DocumentData() { FieldDescriptor = "test 2", FieldValue = 2, FieldVisualData = "https://aka.ms/campus.jpg" });
data = data.Append(new DocumentData() { FieldDescriptor = "test 3", FieldValue = 3, FieldVisualData = "https://aka.ms/campus.jpg" });
this.BindingContext = new ResultPageViewModel(data);
}
}

Get list of CollectionView return Object and put in IIList of Model in xamarin.form

In Xamarin,Try to get list of items in collectionView
My Model is
public class DrugModel
{
public string Name { get; set; }
public bool IsUsed { get; set; }
public int NumberUsed { get; set; }
}
] bind CillectionView to List that returview Api, and when debugger arrive to my change event cant get data and put on my List
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class DrugMissionPage : ContentPage
{
public IList<DrugModel> SelectedDrug;
public DrugMissionPage()
{
InitializeComponent();
}
private void listDrug_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedDrugList =e.CurrentSelection ;
var tyy = selectedDrugList.ToList() as IList<DrugModel>;
foreach (var item in selectedDrugList)
{
SelectedDrug.Add(item);
}
}
And this is my View
<CollectionView
x:Name="listDrug"
VerticalOptions="StartAndExpand"
SelectionMode="Multiple"
ItemsLayout="VerticalList" SelectionChanged="listDrug_SelectionChanged">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10*"></ColumnDefinition>
<ColumnDefinition Width="2*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Frame Padding="10">
<Frame BackgroundColor="AliceBlue" HasShadow="True" CornerRadius="10" Padding="10" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Name}" FontSize="Default" HorizontalOptions="StartAndExpand" Grid.Row="0" Grid.Column="0" Margin="0,10,10,0"></Label>
</StackLayout>
</Frame>
</Frame>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
}
How can I fill
public IList<DrugModel> SelectedDrug;
When debugger pass from
var tyy = selectedDrugList.ToList() as IList<DrugModel>;
foreach (var item in selectedDrugList)
{
SelectedDrug.Add(item);
}
"tyy" will be null
You could use the Cast<class> to convert List to List.
Change:
var tyy = selectedDrugList.ToList() as IList<DrugModel>;
To:
var tyy = selectedDrugList.Cast<DrugModel>();

Xamarin Forms - Multiple items in BindingContext in ViewCell

I have a "Main" page in xaml which contains my cellview.
<ContentPage.Content>
<ListView
Margin="0,15,0,0"
SelectionMode="None"
RowHeight= "150"
ItemsSource="{Binding ObjectItems}">
<ListView.ItemTemplate>
<DataTemplate>
<viewcells:ObjectItemViewCell/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
In my CellView I want to add 2 convertors as BindableContext and to integrate them in some my fields:
<<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:OperaMobile.Views.Postlogin"
xmlns:converterFontFamily="clr-namespace:OperaMobile.Converters"
xmlns:converterColor="clr-namespace:OperaMobile.Converters"
mc:Ignorable="d"
x:Class="OperaMobile.ViewCells.ObjectItemViewCell">
<ViewCell.BindingContext>
<converterFontFamily:BoolToStringConverter x:Key="fontFamilyConverter"/>
<!--<converterColor:BoolToStringConverter x:Key="fontFamilyConverter"/>-->
</ViewCell.BindingContext>
<ViewCell.View>
<StackLayout>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80*"/>
<ColumnDefinition Width="50*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackLayout
Padding="0,10"
Grid.Column="0"
Grid.Row="0"
Margin="15,0"
VerticalOptions="Center"
Orientation="Horizontal">
<Image Source="pin"/>
<Label FontAttributes="Bold" Text="{Binding Label}" Grid.Column="0" Grid.Row="0"/>
</StackLayout>
<StackLayout
Grid.Column="0"
Grid.Row="1"
BindableLayout.ItemsSource="{Binding InfoBox.CountDetailsItemsRows}"
Orientation="Horizontal"
Margin="13,10,0,0">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label FontAttributes="Bold" Text="{Binding BoldLabelTitle}"/>
<Label Text="{Binding LabelValue}"/>
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
<ListView
Margin="15,0"
Grid.Column="0"
Grid.Row="1"
SeparatorVisibility="None"
HasUnevenRows="True"
IsEnabled="False"
VerticalScrollBarVisibility="Never"
ItemsSource="{Binding InfoBox.DetailsObjectInfos}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Grid.Column="1" Orientation="Horizontal" Padding="0" Spacing="0">
<Label FontAttributes="Bold" Text="{Binding BoldLabelTitle}" Padding="0"/>
<Label Text="{Binding LabelValue}"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackLayout VerticalOptions="Start" Grid.Column="1" Grid.RowSpan="2" Spacing="15" Padding="20,10" Orientation="Horizontal" HorizontalOptions="End">
<StackLayout.Resources>
<ResourceDictionary>
<converterColor:BoolToStringConverter
x:Key="colorConverter"
TrueValue="#0275BA"
FalseValue="#949494"/>
<converterFontFamily:BoolToStringConverter
x:Key="fontFamilyConverter"
TrueValue="FA-S"
FalseValue="FA-R"/>
</ResourceDictionary>
</StackLayout.Resources>
<!--"{Binding IsFavorite, Converter={StaticResource fontFamilyConverter}}-->
<Label FontSize="Medium" FontFamily="{Binding IsFavorite, Converter={StaticResource Key=fontFamilyConverter}}" TextColor="{Binding IsFavorite, Converter={StaticResource Key=fontFamilyConverter}}" Text="{StaticResource IconStar}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.ToggleFavoriteObjectCommand}" CommandParameter="{Binding Id}"/>
</Label.GestureRecognizers>
</Label>
<Label FontSize="Medium" Style="{DynamicResource BlueColorStyle}" Text="{StaticResource IconEye}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.ViewObjectDetailsCommand}" CommandParameter="{Binding Id}"/>
</Label.GestureRecognizers>
</Label>
<Label FontSize="Medium" Style="{DynamicResource BlueSolidColorStyle}" Text="{StaticResource IconPin}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.ViewObjectOnMapCommand}" CommandParameter="{Binding Id}"/>
</Label.GestureRecognizers>
</Label>
</StackLayout>
</Grid>
</StackLayout>
</ViewCell.View>
</ViewCell>
this is the VM of my main page where I added viewcell as DataTemplate, so here it is:
public class SearchObjectsViewModel : BaseViewModel, INotifyPropertyChanged
{
public SearchObjectsViewModel()
{
Task.Run(async () => { await GetObjectInstancesList(); });
ToggleFavoriteObjectCommand = new Command(async(data) => await ToggleFavoriteObjects(data));
ViewObjectDetailsCommand = new Command(async (data) => await GetObjectDetails(data));
ViewObjectOnMapCommand = new Command(async (data) => await ViewObjectOnMap(data));
}
#region Properties
private string searchedText;
public string SearchedText
{
get { return searchedText; }
set
{
SetProperty(ref searchedText, value);
ObjectsSearch(searchedText);
}
}
ObservableCollection<CustomPin> _objectItems { get; set; }
public ObservableCollection<CustomPin> ObjectItems
{
get
{
return _objectItems;
}
set
{
if (_objectItems != value)
{
_objectItems = value;
OnPropertyChanged(nameof(ObjectItems));
}
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
public ICommand ViewObjectOnMapCommand { get; set; }
public ICommand ViewObjectDetailsCommand { get; set; }
public ICommand ToggleFavoriteObjectCommand { get; set; }
#endregion
#region Methods
private async Task GetObjectInstancesList()
{
ObjectItems = new ObservableCollection<CustomPin>();
var objectsResponse = await ApiServiceProvider.GetObjectInstances();
Device.BeginInvokeOnMainThread(() =>
{
if (objectsResponse.Succeeded)
{
foreach (var item in objectsResponse.ObjectInstances)
{
CustomPin pinData = new CustomPin();
pinData.Id = item.IdObjectInstance;
pinData.Label = item.ObjectClassName;
pinData.IsFavorite = item.IsFavorite.HasValue ? item.IsFavorite.Value : false;
if (item.Points != null)
{
pinData.Position = new Position(item.Points.FirstOrDefault().Latitude, item.Points.FirstOrDefault().Longitude);
}
else
{
//add polygon
}
foreach (var s in item.Strings)
{
if (s.ShowInBallon)
{
pinData.InfoBox.DetailsObjectInfos.Add(new Models.MapModels.DetailsObjectInfo
{
BoldLabelTitle = s.ClassParameterName + ": ",
LabelValue = s.StringValue
});
}
}
foreach (var i in item.Integers)
{
if (i.ShowInBallon)
{
pinData.InfoBox.DetailsObjectInfos.Add(new Models.MapModels.DetailsObjectInfo
{
BoldLabelTitle = i.ClassParameterName + ": ",
LabelValue = i.IntValue.ToString()
});
}
}
foreach (var date in item.Dates)
{
if (date.ShowInBallon)
{
pinData.InfoBox.DetailsObjectInfos.Add(new Models.MapModels.DetailsObjectInfo
{
BoldLabelTitle = date.ClassParameterName + ": ",
LabelValue = date.DateValue.ToString()
});
}
}
ObjectItems.Add(pinData);
pinData.InfoBox.CountDetailsItemsRows = pinData.InfoBox.DetailsObjectInfos.Count * 85;
}
}
TemporalData.ObjectsData = ObjectItems;
OnPropertyChanged(nameof(ObjectItems));
OnPropertyChanged(nameof(TemporalData.ObjectsData));
});
}
private void ObjectsSearch(string searchedText)
{
if (!string.IsNullOrWhiteSpace(searchedText))
{
var result = TemporalData.ObjectsData.Where(x => x.Label.ToLowerInvariant().Contains(searchedText.ToLowerInvariant())).ToList();
ObjectItems = new ObservableCollection<CustomPin>(result);
}
else
{
ObjectItems = new ObservableCollection<CustomPin>(TemporalData.ObjectsData);
}
OnPropertyChanged(nameof(ObjectItems));
}
private async Task ViewObjectOnMap(object objectId)
{
CustomPin selectedPin = App.SelectedPin = ObjectItems.Where(x => x.Id == Convert.ToInt32(objectId)).FirstOrDefault();
App.GoToPinCommand = new Command(() => App.GoToPinCommand.Execute(selectedPin));
await Shell.Current.GoToAsync(Routes.MapPage);
}
private async Task GetObjectDetails(object objectId)
{
App.SelectedPin = ObjectItems.Where(x => x.Id == Convert.ToInt32(objectId)).FirstOrDefault();
await Shell.Current.GoToAsync(Routes.ItemDetailsPage);
}
private async Task ToggleFavoriteObjects(object objectId)
{
int id = Convert.ToInt32(objectId);
var objectItem = ObjectItems.Where(x => x.Id == id).FirstOrDefault();
var favoriteToggleResponse = await ApiServiceProvider.ToggleFavoriteObjectById(id, !objectItem.IsFavorite);
if (!favoriteToggleResponse.Succeeded)
{
await Shell.Current.DisplayAlert("Error", "Lost communication with server. Try again.", "OK");
}
else
{
ObjectItems.Where(x => x.Id == id).Select(c => { c.IsFavorite = !c.IsFavorite; return c; }).ToList();
}
}
#endregion
}
Im getting the error: BindingCOntext is set more than once.
Other issue that I have is that emulator does not recognize TapGestureRecognizer for example this Label which you can refer to up code:
<Label FontSize="Medium" FontFamily="{Binding IsFavorite, Converter={StaticResource Key=fontFamilyConverter}}" TextColor="{Binding IsFavorite, Converter={StaticResource Key=fontFamilyConverter}}" Text="{StaticResource IconStar}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.ToggleFavoriteObjectCommand}" CommandParameter="{Binding Id}"/>
</Label.GestureRecognizers>
</Label>
I need to put something like Command="{Binding Path=BindingContext.ToggleFavoriteObjectCommand,Source={x:Reference Page}}" but I don't know if I can reference "parrent page" in my case it would be a "Main" page where I invoke cellView.
Cause
You're setting BindingContext twice .
The first : actually the following code does set BindingContext automatically on Cell , the content is the item in list ObjectItems .
<ListView.ItemTemplate>
<DataTemplate>
<viewcells:ObjectItemViewCell/>
</DataTemplate>
</ListView.ItemTemplate>
The second
<ViewCell.BindingContext>
<converterFontFamily:BoolToStringConverter x:Key="fontFamilyConverter"/>
<!--<converterColor:BoolToStringConverter x:Key="fontFamilyConverter"/>-->
</ViewCell.BindingContext>
Solution
Do not set BindingContext inside ViewCell , if you want to use converter , you could add it in page directly .
<ListView
Margin="0,15,0,0"
SelectionMode="None"
RowHeight= "150"
ItemsSource="{Binding ObjectItems}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell BindingContext="{Binding Converter = {StaticResource fontFamilyConverter}}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The command does not trigger because the binding path is incorrect , place those commands into model CustomPin would solve the problem .
The problem is, you are setting converters in BindingContext tag. They needs to be set like this:
<ContentPage.BindingContext>
YOUR BINDING CONTEXT
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<converterFontFamily:BoolToStringConverter x:Key="fontFamilyConverter"/>
<converterColor:BoolToStringConverter x:Key="fontFamilyConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
Your commands not working because of BindingContext error.

Collection was modified; enumeration operation may not execute. Xamarin Forms

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.

Categories