Hi
I'm trying to create a page where I have a list of informations (each row should contain from, to, what and where). I also want to be able to add or remove rows.
Therefore I made a ListView with a DataTemplate fitting to what I need.
I created a DataType containing the four values I need for a row. Then I made an ObservableCollection of this DataType where I put all my rows in.
I'm binding this ObservableCollection as ItemsSource for my ListView and in my DataTemplate I'm binding the values from my Datatype.
When I run my application everything displays as I want it to, also adding/removing rows works. When I edit a field, e.g. the 'fromTime' (TimePicker), the value in this field changes - fine so far.
But now I'm facing a problem I can't get rid of:
It may look nice on the UI, but when I'm looking at the data, there's something wrong..
I have a seperate class for my data containing the ObservableCollection and a standart value (for adding new rows).
When I change a value, no matter in which row, all values of this type in my data-class change! (All of these values in the observableCollection and also the one in my standart value.)
Seems to me like I need to bind to these values inside the observableCollection at the right index.. But I'm new to Xamarin so I don't get it. I tried to find a solution for this in forums, but couldn't find anyone facing the same problem.
Now I hope you can help me as I'm starting to despair
Here's my code:
XAML layout:
Text on top (inside ContentPage), because it's not rendered here ^^
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:xObjectMobile"
x:Class="xObjectMobile.PensumDetailPage"
BindingContext="local:Pensum"
<ContentPage.Content>
<ListView x:Name="p_lstView" RowHeight="160" SeparatorColor="DodgerBlue" ItemsSource="{Binding pensumFields}">
<ListView.Header>
<StackLayout Orientation="Horizontal" HorizontalOptions="Fill">
<Label x:Name="p_lblPensumDetailPage" Text="Pensum" HorizontalOptions="Center" Margin="20" FontSize="Large"/>
<DatePicker x:Name="p_dpPensumDate" HorizontalOptions="EndAndExpand" Date="{Binding selectedDate}" IsEnabled="False"/>
</StackLayout>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" HorizontalOptions="Fill" Margin="15,0,15,0">
<StackLayout Orientation="Horizontal">
<Label x:Name="p_lblFrom" Text="Von" Margin="0,10,0,0"/>
<TimePicker x:Name="p_tpFromTimePensum" HorizontalOptions="FillAndExpand" Margin="0,15,0,0"/>
<Label x:Name="p_lblTo" Text="Bis" Margin="0,10,0,0"/>
<TimePicker x:Name="p_tpToTimePensum" HorizontalOptions="FillAndExpand" Time="{Binding toTime}" Margin="0,15,0,0"/>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label x:Name="p_lblType" Text="Art"/>
<Picker x:Name="p_picType" HorizontalOptions="FillAndExpand" SelectedIndex="{Binding selectedType}" ItemsSource="{x:Static local:Pensum.pensumTypes}"/>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label x:Name="p_lblLocation" Text="Ort"/>
<Entry x:Name="p_entLocation" HorizontalOptions="FillAndExpand" Text="{Binding location}"/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Footer>
<StackLayout Orientation="Horizontal" HeightRequest="60" VerticalOptions="End">
<Image x:Name="p_btnAddField" Source="@drawable/plus.png" Margin="5">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="p_btnAddField_Clicked"/>
</Image.GestureRecognizers>
</Image>
<Image x:Name="p_btnRemoveField" Source="@drawable/minus.png" Margin="5">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="p_btnRemoveField_Clicked"/>
</Image.GestureRecognizers>
</Image>
<Button x:Name="p_btnSave" Text="Speichern" Clicked="p_btnSave_Clicked" FontSize="Large" HorizontalOptions="EndAndExpand"/>
</StackLayout>
</ListView.Footer>
</ListView>
</ContentPage.Content>
DataType:
using System;
namespace xObjectMobile
{
public class PensumField
{
public TimeSpan fromTime { get; set; }
public TimeSpan toTime { get; set; }
public int selectedType { get; set; }
public string location { get; set; }
}
}
Data Class:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace xObjectMobile
{
public class Pensum
{
public DateTime selectedDate { get; set; } = new DateTime(1998, 11, 21); //for now just a fixed date, not important
public PensumField standartPensumField { get; set; } = new PensumField //the standart field for adding a new row
{
fromTime = new TimeSpan(0, 8, 0, 0),
toTime = new TimeSpan(0, 16, 0, 0),
selectedType = 1,
location = "Berndorf"
};
public static List<String> pensumTypes { get; set; } //list for the picker to choose from
public ObservableCollection<PensumField> pensumFields { get; set; } //ObservableCollection where the rows are stored in
public Pensum()
{
pensumFields = new ObservableCollection<PensumField>();
pensumTypes = new List<String>();
//Fill PensumTypes
pensumTypes.Add("type1");
pensumTypes.Add("type2");
pensumTypes.Add("type3");
}
}
}
Code behind:
using System.Linq;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace xObjectMobile
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class PensumDetailPage : ContentPage
{
Pensum data = new Pensum();
public PensumDetailPage()
{
InitializeComponent();
BindingContext = data; //setting the binding context (correct?)
setStandartPensumFields(); //create the first three rows
}
private void p_btnSave_Clicked(object sender, EventArgs e)
{
//To be added
}
private void p_btnAddField_Clicked(object sender, EventArgs e)
{
if (data.pensumFields.Count < 9)
{
data.pensumFields.Add(data.standartPensumField);
}
}
private void p_btnRemoveField_Clicked(object sender, EventArgs e)
{
if (data.pensumFields.Count >= 1)
{
data.pensumFields.Remove(data.pensumFields.Last()); //also very strange: it removes the top one in the list
}
}
private void setStandartPensumFields()
{
for (int i = 0; i < 3; i++)
{
data.pensumFields.Add(data.standartPensumField);
}
}
}
}