I need to populate a custom ListView with data from a downloaded JSON.
This is the custom ListView I created:
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<StackLayout Orientation="Vertical" Spacing="5" VerticalOptions="Center">
<StackLayout Orientation="Horizontal">
<Label Text="{Binding TradeDate}" Padding="25,0,0,0" FontSize="19" TextColor="Black"></Label>
<Label Text="{Binding TradeGain}" Padding="0,0,25,0" FontSize="19" FontAttributes="Bold" TextColor="Green" HorizontalOptions="EndAndExpand"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding TradeQty}" Padding="25,0,0,0" FontSize="16"></Label>
<Label Text="{Binding TradeEff}" Padding="0,0,25,0" FontSize="16" HorizontalOptions="EndAndExpand"></Label>
</StackLayout>
</StackLayout>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Then I set the BindingContext to the class with the ItemSource:
<ContentPage.BindingContext>
<local:TradesView>
<x:Arguments>
<x:String>cacca</x:String>
</x:Arguments>
</local:TradesView>
</ContentPage.BindingContext>
This is the TradeView class seen here in the BindingContext:
Unfortunately, I can't download the JSON from here since it requires authentication which of course is handled by another ContentPage.
public class TradesView
{
public ObservableCollection<Trade> Trades { get; set; }
public TradesView(string trades)
{
Trades = new ObservableCollection<Trade>();
JArray jArray = JArray.Parse(trades);
foreach (JObject trade in jArray){
Trades.Add(new Trade(trade["date"].ToString(), trade["gain"].ToString(), trade["depth"].ToString(), "0"));
}
}
}
The problem is that now I have no idea on how to proceed since there seems no way of passing a variable as an argument to the TradeView constructor which should handle the JSON and populate the ObservableCollection with what I need.
I just think my procedure is wrong and I should scrap a lot of what I did, but then I genuinely have no idea on how to solve this.
CodePudding user response:
There are several ways to solve this. Here is one, which uses a "Factory method" (Create
) to create the page that contains your view, then set that page's Items
property.
This makes sense if there is only one page that contains that view.
Usage:
var names = new List<string> { "One", "Two", "Three", "Four" };
MainPage = SelfBoundPageWithCollection.Create(names);
SelfBoundPageWithCollection.xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TestXFUWP.SelfBoundPageWithCollection">
<ContentPage.Content>
<StackLayout>
<CollectionView ItemsSource="{Binding Items}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding Name}" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
SelfBoundPageWithCollection.xaml.cs:
public partial class SelfBoundPageWithCollection : ContentPage
{
public SelfBoundPageWithCollection()
{
InitializeComponent();
BindingContext = this;
}
public ObservableCollection<ItemModel> Items {
get => _items;
set {
_items = value;
OnPropertyChanged();
}
}
private ObservableCollection<ItemModel> _items;
public static SelfBoundPageWithCollection Create(List<string> names)
{
var it = new SelfBoundPageWithCollection();
it.FillItems(names);
return it;
}
// Can call this directly later, to replace Items collection.
public void FillItems(List<string> names)
{
var items = new ObservableCollection<ItemModel>();
foreach (var name in names) {
items.Add(new ItemModel(name));
}
Items = items;
}
}
Or to have a separate "ViewModel" (MVVM), do it like this:
Usage:
var names = new List<string> { "One", "Two", "Three", "Four" };
MainPage = PageWithCollection.Create(names);
PageWithCollection.xaml.cs:
public partial class PageWithCollection : ContentPage
{
public PageWithCollection()
{
InitializeComponent();
BindingContext = new ViewModelWithItems();
}
public static PageWithCollection Create(List<string> names)
{
var it = new PageWithCollection();
var vm = (ViewModelWithItems)it.BindingContext;
vm.FillItems(names);
return it;
}
}
ViewModelWithItems.cs:
public class ViewModelWithItems : Xamarin.Forms.BindableObject
{
public ViewModelWithItems()
{
}
public ObservableCollection<ItemModel> Items {
get => _items;
set {
_items = value;
OnPropertyChanged();
}
}
private ObservableCollection<ItemModel> _items;
public void FillItems(List<string> names)
{
var items = new ObservableCollection<ItemModel>();
foreach (var name in names) {
items.Add(new ItemModel(name));
}
Items = items;
}
}
Both of the above refer to this model:
ItemModel.cs:
public class ItemModel
{
public ItemModel(string name)
{
Name = name;
}
public string Name { get; set; }
}