Update the object of ObservableCollection is not reflecting the in the UI - c#

I am binding ObservableCollection with CollectionView.
<CollectionView ItemsSource="{Binding LeftExercises}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:ExerciseModel">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="4*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Grid.Row="0" Text="{Binding SetNumber}" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="Black" FontSize="Medium" />
<Label Grid.Column="1" Grid.Row="0" Text="{Binding Weight}" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="Black" FontSize="Medium" />
<Label Grid.Column="2" Grid.Row="0" Text="{Binding Reps}" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="Black" FontSize="Medium" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
private ObservableCollection<ExerciseModel> _leftExercises;
public ObservableCollection<ExerciseModel> LeftExercises
{
get => _leftExercises;
set
{
if (_leftExercises != value)
{
_leftExercises = value;
OnPropertyChanged(nameof(LeftExercises));
}
}
}
When I add a new object to the Collection, it will reflect in my UI but whenever I try to update the value of any object, it will not reflect.
This is my model
public class ExerciseModel
{
public int SetNumber { get; set; }
public decimal Weight { get; set; }
public int Reps { get; set; }
public ExerciseType ExerciseType { get; set; }
public Side Side { get; set; }
}
I am incrementing the Reps (update Reps property) from the below command.
private Command _dummyLeftIncreaseRepsCommand;
public Command dummyLeftIncreaseRepsCommand
{
get
{
return _dummyLeftIncreaseRepsCommand ??= new Command(() =>
{
ExerciseModel lastObj = LeftExercises.Last(x => x.Side == SharedVM.ActiveSide);
lastObj.Reps += 1;
});
}
}

Your ExerciseModel class needs to implement INotifyPropertyChanged.
To do so, simply add the interface name to your class code, like this:
class MyClass : INotifyPropertyChanged
Alternatively, you can set the ItemsSource for the object again. Doing so will update the visual as well. You can do this at runtime like this:
XAML file:
<CollectionView x:Name="MyView">[...]
Code in background:
MyView.ItemsSource = MyCollectionVar;

I advise you to use CommunityToolkit.MVVM and CommunityToolkit.MAUI, when you try to bind commands, observable properties and collections to your XAML.
The benefit of this will be that you wont have to write walls of code, and spend hours to figure out why it is not working.
It saves you time, that you can put in something useful, instead of dealing with boilerplate code.

Related

Binding to a parent's context in xamarin forms

I just can't get my head around it. My brain melts trying to understand how to bind to a parent's context.
So here I have a (relatively) simple object:
public class BinDefinition
{
public string labelAdresse { get; set; }
public InventoryItem inventoryItem { get; set; }
public List<BinContent> binContents { get; set; }
public List<InventoryProduct> productsinBinContent { get; set; }
public bool showDeleteButton { get; set; }
public bool showTransferButton { get; set; }
public ObservableCollection<ListItem> Items { get; set; }
}
then I have my view model that has two of these bindefinitions.
public class viewModel
{
public binDefinition primaryBin { get; set; }
public binDefinition secondaryBin { get; set; }
}
And finally, the relevant xaml part:
<ListView x:Name="ItemsListView" Grid.Row="1"
ItemsSource="{Binding Items}"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
RefreshCommand="{Binding LoadItemsCommand}"
IsPullToRefreshEnabled="true"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
CachingStrategy="RecycleElement"
ItemTapped="ItemsListView_ItemTapped"
Grid.RowSpan="2"
>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid BackgroundColor="LightBlue">
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="60"></ColumnDefinition>
<ColumnDefinition Width="60"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Text="{Binding Name}" LineBreakMode="WordWrap" FontAttributes="Bold" FontSize="16" HorizontalOptions="FillAndExpand" />
<Label Grid.Row="1" Text="{Binding EANReference}" LineBreakMode="WordWrap" TextColor="Gray" FontSize="16" HorizontalOptions="FillAndExpand" />
<Label Grid.Row="2" Text="{Binding QuantityDisplay}" LineBreakMode="WordWrap" TextColor="DarkBlue" FontSize="16" HorizontalOptions="FillAndExpand" />
<Button Grid.RowSpan="3" Grid.Column="1" Text="Info" Clicked="btnInfos_Clicked" CommandParameter="{Binding EAN}"/>
<Button Grid.RowSpan="3" Grid.Column="2" Text="Del" Clicked="btnDel_Clicked" CommandParameter="{Binding Id}" IsVisible="{Binding BindingContext.primaryBin.showDeleteButton, Source={x:Reference Inv2PageMainContent}}"/>
<Button Grid.RowSpan="3" Grid.Column="2" Text="Tra" Clicked="btnTransfer_Clicked" CommandParameter="{Binding Id}" IsVisible="{Binding BindingContext.primaryBin.showTransferButton, Source={x:Reference Inv2PageMainContent}}"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I am trying to bind the two final button so that the show up or hide depending on the state of the boolean available in BinDefinition. But at that point, the datacontext of said button is a ListItem (from the Items in the viewModel).
I just don't know how to call back the direct parent to use its property.
edit: apologies, it seems I failed to provide sufficient informations.
the inv2MainpageContent is the name of the page. x:Name = inv2MainPageContent.
The BindingContext of the page is an instance of the viewModel. That viewModel contain two binDefinitions. And in that bin Definition are multiple properties. The three that are important to me are the bool ShowDelete/ShowTransfer and the Collection Items.
The List view in my view has dug into the primaryBin and uses "primaryBin.Items" as its ItemSource. The thing is, I would like to bind the visibility of these objects to the the primaryBin.ShowDelete/ShowTransfer.

Xamarin Forms Command Binding inside ListView is not working

i'm trying to bind a command to a button inside a listView, but without success. I follow all other answers posted here, like this one:
Xamarin Forms Button Command binding inside a ListView
The actual result is that nothing happens. A thing that i notice is that visual studio, when i type after x:Reference suggests me just GridWebcam, like if it doesn't see other reference elements. What can i do?
Here my code:
<ContentPage
...
x:Name="WebcamList">
<ContentPage.Resources>
...
<ContentPage.Content>
<ListView ItemsSource="{Binding ListOfWebcam}"
SeparatorVisibility="None"
CachingStrategy="RecycleElement"
RowHeight="250"
VerticalOptions="FillAndExpand"
x:Name="ListWebcam">
<ListView.Header>
<StackLayout x:Name="HeaderStackLayout"
Padding="5,25,0,30"
Orientation="Horizontal"
HorizontalOptions="FillAndExpand">
<Label x:Name="LabelHeader"
Text="Webcam:"
FontSize="Large"
FontAttributes="Bold"
TextColor="{x:Static statics:Palette.PrimaryColor}"
VerticalOptions="Center"
HorizontalOptions="Start" Margin="10,0,0,0"/>
</StackLayout>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<controls:ExtendedViewCell IsEnabled="False">
<controls:ExtendedViewCell.View>
<Grid x:Name="GridWebcam">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Frame Grid.Column="1"
Grid.RowSpan="2"
CornerRadius="20"
BackgroundColor="{x:Static statics:Palette.PrimaryColor}"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
HasShadow="True"
Margin="5,10">
<StackLayout>
<Label Text="{Binding t_str_vid,Converter={StaticResource WebcamNameConverter}}"
FontSize="Medium"
TextColor="White"
FontAttributes="Bold"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
</Label>
<Label TextColor="White"
FontSize="Medium"
Text="{Binding direzione,Converter={StaticResource DirectionToStringConverter}}"/>
<StackLayout Orientation="Horizontal">
<ffimageloading:CachedImage LoadingPlaceholder="Rolling.gif"
DownsampleToViewSize="False"
VerticalOptions="FillAndExpand"
HorizontalOptions="StartAndExpand"
Source="{Binding image1}"/>
<iconize:IconButton Text="fas-play-circle"
FontSize="50"
HorizontalOptions="EndAndExpand"
VerticalOptions="EndAndExpand"
TextColor="White"
Command="{Binding BindingContext.OpenVideoWebcamCommand, Source={x:Reference WebcamList}}"
CommandParameter="{Binding .}"
BackgroundColor="Transparent"/>
</StackLayout>
</StackLayout>
</Frame>
</Grid>
</controls:ExtendedViewCell.View>
</controls:ExtendedViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
```
public class WebcamListViewModel : BaseViewModel
{
public ICommand OpenVideoWebcamCommand { set; get; }
private List<Webcam> _ListOfWebcam { get; set; }
public List<Webcam> ListOfWebcam
{
get { return _ListOfWebcam; }
set
{
_ListOfWebcam = value;
OnPropertyChanged();
}
}
private Task DownloadFramesTask;
CancellationTokenSource tokenSourceDownloadFrames = new CancellationTokenSource();
CancellationToken cancellationTokenDownloadFrames;
public WebcamListViewModel(INavigationService navigationService, IApiAutostradeManagerFactory apiAutostradeManagerFactory) : base(navigationService,apiAutostradeManagerFactory)
{
OpenVideoWebcamCommand = new Command<Webcam>(async (webcam) => {
await navigationService.NavigateAsync(Locator.WebcamVideoPopUpPage);
Messenger.Default.Send(new InfoWebcamVideoMessage(webcam.c_mpr, webcam.c_uuid, webcam.t_str_vid));
});
}
Well it could be related to this mysterious controls:ExtendedViewCell of yours :)
Also did you disable the ListView selection: <ListView ... SelectionMode="None" /> ?
As Roubachof said that I don't know if it is related to controls:ExtendedViewCell,please check if you have binding BindingContext, then you can take a look the following code:
<StackLayout>
<ListView x:Name="listview1" ItemsSource="{Binding persons}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Id}" />
<Label Text="{Binding name}" />
<Button
Command="{Binding BindingContext.command, Source={x:Reference listview1}}"
CommandParameter="{Binding Id}"
Text="Delete item" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
public partial class Page1 : ContentPage
{
public ObservableCollection<person> persons { get; set; }
public RelayCommand1 command { get; set; }
public Page1 ()
{
InitializeComponent ();
persons = new ObservableCollection<person>();
for(int i =0;i<20;i++)
{
person p = new person()
{
Id = i,
name = "cherry" + i
};
persons.Add(p);
command = new RelayCommand1(obj => method1((int)obj));
}
this.BindingContext = this;
}
public void method1(int Id)
{
persons.RemoveAt(Id);
//IEnumerable<person> list = persons.Where(x => x.Id == Id);
//foreach (person m in list)
//{
//}
}
}
public class person
{
public int Id { get; set; }
public string name { get; set; }
}

Xamarin Forms ListView grouping bind issue

I have been trying to play around Xamarin Forms for a while and then came across to the Listview Grouping. I am not getting done its showing blank list. Please give me help to find where I am going wrong? Thanks in advance
However, My class domain looks like:
public class LineItemTaxDto
{
public int InvoiceLineItemId { get; set; }
public int InvoiceId { get; set; }
public int TaxId { get; set; }
public decimal TaxRate { get; set; }
public decimal TaxAmount { get; set; }
public string TaxName { get; set; }
}
My View Model property look like
public IEnumerable<KeyValuePair<string, ObservableCollection<LineItemTaxDto>>> ReceiptTaxList { get; set; }
My expecting result look like:
My xaml code below
<ListView x:Name="TaxListView"
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="2"
ItemsSource="{Binding Invoice.ReceiptTaxList}"
IsGroupingEnabled="true">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Key}" />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid RowSpacing="0" ColumnSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Label Text="{Binding TaxName}" Grid.Row="0" Grid.Column="0" FontSize="22" FontFamily="{x:Static resources:Fonts.ArialMTFont}" HorizontalOptions="End" HorizontalTextAlignment="End" Margin="0,5,0,5" />
<Label Grid.Row="0" Grid.Column="1" Text="{Binding TaxAmount, Converter={Helpers:CurrencyAmountConverter}}" FontSize="22" FontFamily="{x:Static resources:Fonts.ArialMTFont}" HorizontalOptions="End" Margin="0,5,0,5" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
EDIT
I am set value in view will appear method
Invoice.ReceiptTaxList = Invoice.InvoiceLineItems.Select(x => { return new KeyValuePair<string, ObservableCollection<LineItemTaxDto>>(x.TaxName, x.LineItemTaxes); });
The value was set properly
I have solved this tricky code not using grouping but now its work as expected
My ViewModel Code
var TaxList = Invoice.InvoiceLineItems.Where(x => x.TaxId > 1).GroupBy(y=>y.TaxId > 1).Select(x =>
{
return new KeyValuePair<LineItemTaxDto, ObservableCollection<LineItemTaxDto>>(new LineItemTaxDto()
{
InvoiceLineItemId = x.First().Id,
InvoiceId = x.First().InvoiceId,
TaxId = x.First().TaxId,
TaxRate = x.First().TaxRate,
TaxAmount = x.Sum(a=>a.TaxAmount),
TaxName = taxlabel + " (" + x.First().TaxName + ")"
}, x.First().LineItemTaxes);
});
var taxes = new ObservableCollection<LineItemTaxDto>();
foreach (var tax in TaxList.GroupBy(tax => tax.Key.TaxId).Select(grp => grp.First()))
{
taxes.Add(tax.Key);
foreach (var subtax in tax.Value.Where(x => x.TaxId > 0))
{
taxes.Add(subtax);
}
}
Invoice.ReceiptTaxList = taxes;
My Xaml Code
<ListView
x:Name="TaxListView"
ItemsSource="{Binding Invoice.ReceiptTaxList}"
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="2"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
SeparatorVisibility="None"
HasUnevenRows="false"
RowHeight="35"
>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid RowSpacing="0" ColumnSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="{Binding TaxName}" FontSize="22" FontFamily="{x:Static resources:Fonts.ArialMTFont}" HorizontalOptions="End" HorizontalTextAlignment="End" Margin="0,5,0,5" />
<Label Grid.Row="0" Grid.Column="1" Text="{Binding TaxAmount, Converter={Helpers:CurrencyAmountConverter}}" FontSize="22" FontFamily="{x:Static resources:Fonts.ArialMTFont}" HorizontalOptions="End" Margin="0,5,0,5" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
You must use a list of list as items source on listview to get it working. I recommend you to create a class with the properties you want to show at header like this:
public class TaxesObservableCollection<T> : ObservableCollection<T> // Think about to implement INotifyPropertyChanged too, I guess it will be usefull
{
public TaxesObservableCollection(IEnumerable<T> collection, string taxGroupName) : base(collection)
{
TaxGroupName = taxGroupName;
}
private bool taxGroupName;
public bool TaxGroupName
{
get { return taxGroupName; }
set { taxGroupName = value; }
}
}
In your view model:
public IEnumerable<TaxesObservableCollection<LineItemTaxDto>> ReceiptTaxList { get; set; }
Your ListView:
(...) // The rest of it as you did
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding TaxGroupName}" />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
(...) // The rest of it as you did
And you fill it this way:
Invoice.ReceiptTaxList = Invoice.InvoiceLineItems.Select(x => { return new TaxesObservableCollection<LineItemTaxDto>(x.LineItemTaxes, x.TaxName); }).ToList();
It should works, please let me know if is that what you wanted.

Put data from JSON file in a listview and bind them to a grid in xaml

I have a DetailPage where I have put a ContenView into. In this ContenView I implemented a Grid because I wanted something like Refresh-Button for the JSON-ListView. That worked really well so far.
With your help I've accomplished to parse the JSON Data and put it into a ListView. My plan was to put this ListView in the 2nd row of my first Grid. I did another Grid in the first Grid where I tried to push the ListView inside, but the fields are empty...
Screenshot: http://imgur.com/a/Tj0kd
Here is my XAML Code from the DetailPage
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ODC_Foto_ConWin_v1.YardList"
xmlns:local="clr-namespace:ODC_Foto_ConWin_v1"
Title="YardList"
BackgroundColor="LightGray">
<ContentPage.Content>
<Grid BackgroundColor="#004d93">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Grid.Row="0" Text="File-Age: < 12m" FontSize="Small" Margin="5,5,0,0" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" HorizontalOptions="Start" VerticalOptions="Center" TextColor="White" FontAttributes="Bold"/>
<Image Source="sync.png" Grid.Column="1" Grid.Row="0" Scale="0.7" HorizontalOptions="End" VerticalOptions="Center" Margin="0,5,0,0"/>
<Label Grid.Column="2" Grid.Row="0" Text="Sync" FontSize="Small" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" HorizontalOptions="End" VerticalOptions="Center" TextColor="White" Margin="0,5,5,0" FontAttributes="Bold"/>
<Button Grid.Column="1" Grid.Row="0" Grid.ColumnSpan="2" BackgroundColor="Transparent" VerticalOptions="Center" Clicked="yardListSyncButton_Clicked"/>
<Grid Grid.ColumnSpan="3" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListView x:Name="listViewJson">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Grid.Column="0" Text="{Binding id}" BackgroundColor="Transparent" />
<Label Grid.Column="1" Text="{Binding kfz_nr}" BackgroundColor="Transparent" />
<Label Grid.Column="2" Text="{Binding kfz_kz}" BackgroundColor="Transparent" />
<Label Grid.Column="3" Text="{Binding timestamp}" BackgroundColor="Transparent" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
<ActivityIndicator x:Name="ProgressLoader" IsVisible="True" IsRunning="True"/>
</Grid>
</ContentPage.Content>
<ContentPage.ToolbarItems>
<ToolbarItem Icon="add.png" Activated="ToolbarItem_Activated"/>
</ContentPage.ToolbarItems>
</ContentPage>
and here is my C# Code:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace ODC_Foto_ConWin_v1
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class YardList : ContentPage
{
public YardList()
{
InitializeComponent();
GetJSON();
}
private void yardListSyncButton_Clicked(object sender, EventArgs e)
{
GetJSON();
}
private void ToolbarItem_Activated(object sender, EventArgs e)
{
// code for manual process
}
public async void GetJSON()
{
var client = new System.Net.Http.HttpClient();
var response = await client.GetAsync("http://x.x.x.x/xample.JSON");
string json = await response.Content.ReadAsStringAsync();
RootObject rootObject = new RootObject();
ListView listViewJson = new ListView();
if (json != "")
{
rootObject = JsonConvert.DeserializeObject<RootObject>(json);
}
listViewJson.ItemsSource = rootObject.process;
ProgressLoader.IsVisible = false;
}
public class Process
{
public string id { get; set; }
public string fzg_nr { get; set; }
public string fzg_kz { get; set; }
public string timestamp { get; set; }
}
public class RootObject
{
public string file_timestamp { get; set; }
public List<Process> process { get; set; }
}
}
}
Is this something about wrong DataBinding? Am I initiating the ItemSource at the wrong point?! Because when I set the datatemplate in the GetJSON() method the data is visible...
So far i tried a few examples but at some point there must be a little mistake. I am new programming (I'm normally a systemadministrator) so I don't where to start looking for the mistakes.
Any help is really appreciated.
Thanks in advance,
Paul
Short answer: don't create new list, use existing one - just remove ListView listViewJson = new ListView(); from GetJSON and it should work.
Long answer
In your XAML you have:
<ListView x:Name="listViewJson">
and in your GetJSON method you are creating NEW ListView and setting ItemSource like this:
public async void GetJSON()
{
ListView listViewJson = new ListView();
(...)
listViewJson.ItemsSource = rootObject.process;
}
So you have 2 ListViews, one in XAML, and one in GetJSON method. Your ListView in XAML has the same name like ListView in GetJSON method (listViewJson). Because ListView created in method is 'closer' in line listViewJson.ItemsSource = rootObject.process then ListView created in XAML,you are setting ItemSource of newly created ListView that was not added to your ContentView.
EDIT:
I see couple other minor issues in your code, not related to the question but because you are learning, I thing it's worth to point them out:
Labels in your ListView template do not have Grid as direct parent so Grid.Column="0" does not have any effect
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Grid.Column="0">
In C# it is a common practice to use PascalCase naming style for properties. I think that you did this: public string timestamp { get; set; } because of json format. You can use JsonPropertyAttribute to set your mapping between C# and json like this:
[JsonProperty("timestamp")]
public string Timestamp { get; set; }
You are hiding ProgressLoader at the end of GetJSON but you are not showing it at the beginning, so it is visible only on your fist GetJSON call (so in constructor).
now your are using code behind and it is totally ok when you are starting with Xamarin. Later on I would suggest you go take a look at MVVM pattern.

xamarin Binding To List

I'm new to Xamarin and C#, so forgive me if my code is crap.
So essentially I'm trying to create a simple page that displays a list of course names, and allows a button to insert or remove items from the list within the view.
As of now the program builds and runs but the view does not display the contents of the list. Any help would be greatly appreciated. Thanks!
Here's the view:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="65" />
<RowDefinition Height="*"/>
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Frame OutlineColor="Black" Grid.Row="0" Grid.ColumnSpan="2">
<Label Text= "My Courses" FontSize="20" TextColor="Black" HorizontalTextAlignment="Center"/>
</Frame>
<Frame OutlineColor="Black" Grid.Row="1" Grid.ColumnSpan="2">
<ListView x:Name="CourseList" ItemsSource="{Binding GetCourseList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Label FontSize="14" Text="{Binding Name}" TextColor="Black" Grid.Row="0" Grid.Column="0"/>
<Button FontSize="14" Text="X" TextColor="Black" Grid.Row="0" Grid.Column="1"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Frame>
<Button Text="+" FontSize="20" TextColor="Green" BackgroundColor="Silver"
HorizontalOptions="Fill" VerticalOptions="Center"
Grid.Row="2" Grid.ColumnSpan="2"
/>
</Grid>
Here's the View.cs code:
public partial class MainPage : ContentPage
{
MainPageViewModel vm;
public MainPage()
{
vm = new MainPageViewModel();
vm.AddCourse();
BindingContext = vm;
InitializeComponent();
}
Here's the View Model:
class MainPageViewModel
{
public string Name { get; set; }
public List<Course> Courses;
public MainPageViewModel()
{
Courses = new List<Course>();
}
public List<Course> GetCourseList()
{
return Courses;
}
public void AddCourse()
{
Course NewCourse = new Course();
NewCourse.Name = "New Course Added";
Courses.Add(NewCourse);
}
}
Finally, Here's my Model:
public class Course
{
public string Name { get; set; }
}
So I have been able to display a list using this code but I do not believe this will allow me to add or delete from the list and update the view via button click (Correct me if I'm wrong).
public List<Course> Courses{
get{
return new List<Course>(){
new Course(){Name = "Added a course"}
};
}
I think I just found my error and solution.
public List<Course> Courses{
get{
return new List<Course>(){
new Course(){Name = "Added a course"}
};
}
Because Courses is "read only" and now being bound to the view I created a member variable List VMCourse to hold the actually list of objects and am using Courses to be bounded to and read into the view.
It appears to work, but I still need to test it with button features for adding and deleting from the list. Does this look like a decent solution to you guys?
Thanks in advance!
class MainPageViewModel
{
public string Name { get; set; }
public List<Course> VMCourse;
//This is now bound to the view's listview
public List<Course> Courses {
get
{
return VMCourse;
}
}
public MainPageViewModel()
{
VMCourse = new List<Course>();
}
public void AddCourse()
{
Course NewCourse = new Course();
NewCourse.Name = "New Course Added";
VMCourse.Add(NewCourse);
}
You cannot bind a list to a method. You should use binding with properties. So to fix this you only need to change
public List<Course> GetCourseList()
{
return Courses;
}
To
public List<Course> GetCourseList
{
get { return Courses; }
}
But, as it's mentioned in the comments not any property is suitable to be used with binding unless you know what you are doing so search about binding.

Categories

Resources