I am trying to create different tabs with different nested ListViews binding to ObservableCollection.
This is getting a bit over my head. It should be very simple to solve.
This is how my TabbedPage xaml looks like
<TabbedPage 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"
mc:Ignorable="d"
x:Class="scorePredict.Views.TabbedItemsPage" ItemsSource="{Binding Things}">
<!--Pages can be added as references or inline-->
<TabbedPage.ItemTemplate>
<DataTemplate>
<ContentPage Title="{Binding description}">
<StackLayout>
<ListView ItemsSource="{Binding DetailedViewModel.sortedItems}">
<ListView.HeaderTemplate >
<DataTemplate>
<Grid BackgroundColor="Black">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="Time" Grid.Column="0" Margin="5,0,0,0" TextColor="Gold" HorizontalOptions="StartAndExpand" HeightRequest="20" WidthRequest="50"/>
<Label Text="Host" Grid.Column="1" TextColor="Gold" HorizontalOptions="CenterAndExpand" Margin="0,0,170,0"/>
<Label Text="Guest" Grid.Column="1" TextColor="Gold" HorizontalOptions="CenterAndExpand" Margin="110,0,0,0"/>
<Label Text="TIP" HorizontalOptions="EndAndExpand" TextColor="Gold" Grid.Column="1"/>
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.Header >
<StackLayout Padding="10,5,0,5" BackgroundColor="Green" Orientation="Horizontal">
<Label Text="{Binding Name}" />
<Label Text="{Binding Description}" FontSize="Small"/>
</StackLayout>
</ListView.Header>
<ListView.GroupHeaderTemplate >
<DataTemplate>
<ViewCell Height="30">
<StackLayout Orientation="Horizontal"
BackgroundColor="Goldenrod"
VerticalOptions="FillAndExpand">
<Image Source="{Binding imagePath}" VerticalOptions="Center" HorizontalOptions="Start" HeightRequest="20" WidthRequest="20"/>
<Label Text="{Binding Intro} " VerticalOptions="Center"/>
<Label Text="{Binding Summary}" VerticalOptions="Center"/>
<Label Text="TIP" VerticalOptions="Center" HorizontalOptions="EndAndExpand"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid Padding="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding Time}" Grid.Column="0"></Label>
<Label Text="{Binding TeamOne}" Grid.Column="1" HorizontalTextAlignment="End" HorizontalOptions="CenterAndExpand" Margin="0,0,170,0"></Label>
<Label Text="{Binding ScoreTeamOne}" Grid.Column="1" TextColor="White" HorizontalOptions="CenterAndExpand" HorizontalTextAlignment="Center" Margin="0,0,50,0" WidthRequest="20" BackgroundColor="Gray"></Label>
<Label Text="{Binding ScoreTeamTwo}" Grid.Column="1" TextColor="White" HorizontalOptions="CenterAndExpand" HorizontalTextAlignment="Center" Margin="0,0,5,0" WidthRequest="20" BackgroundColor="Gray"></Label>
<Label Text="{Binding TeamTwo}" Grid.Column="1" HorizontalTextAlignment="Start" HorizontalOptions="CenterAndExpand" Margin="110,0,0,0"></Label>
<Label Text="{Binding Tip}" Grid.Column="1" HorizontalOptions="EndAndExpand" WidthRequest="20" HorizontalTextAlignment="Center" TextColor="White" BackgroundColor="{Binding TipBGColor}"></Label>
</Grid>
</ViewCell.View>
</ViewCell>
<!--<TextCell Text="{Binding Name}" Detail="{Binding Description}"></TextCell>-->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
</DataTemplate>
</TabbedPage.ItemTemplate>
</TabbedPage>
This is the background code
public TabbedItemsPage()
{
InitializeComponent();
BindingContext = new CurrentStatusDeviceViewModel();
}
public class CurrentStatusDeviceViewModel
{
public ObservableCollection<TabViewModel> Things { set; get; }
public CurrentStatusDeviceViewModel()
{
// Here I create three demo pages
Things = new ObservableCollection<TabViewModel>();
for (int i = 0; i < 7; i++)
{
Things.Add(new TabViewModel(i.ToString()) { description = "description" + i });
}
}
}
public class TabViewModel
{
public string description { set; get; }
public string TabID { set; get; }
public CurrentStatusDeviceDetailedViewModel DetailedViewModel { set; get; }
public TabViewModel(string tabID)
{
TabID = tabID;
// Pass Tab ID to the second view model
DetailedViewModel = new CurrentStatusDeviceDetailedViewModel(tabID);
}
}
public class CurrentStatusDeviceDetailedViewModel
{
public string CurrentID { set; get; }
public ObservableCollection<Titles> sortedItems { get; set; }
public ObservableCollection<Item> items { get; set; }
public CurrentStatusDeviceDetailedViewModel(string tabId)
{
CurrentID = tabId;
// I simulate the lists here
sortedItems = new ObservableCollection<Titles>();
items = new ObservableCollection<Item>();
for (int i = 0; i < 5; i++)
{
for (int x = 0; x < 10; x++)
{
items.Add(new Item { Time = CurrentID + i, TeamOne = "Barcelona", ScoreTeamOne = "2", TeamTwo = "Real Madrid", ScoreTeamTwo = "1" });
}
sortedItems.Add(new Titles(items.ToList()) { Intro = "This is a big header", Summary = "This is the end" });
items.Clear();
}
}
}
And these are my classes for the lists
public class Titles : ObservableCollection<Item>
{
//public List<Matches> Monkeys { get; set; }
public string Intro { get; set; }
public string Summary { get; set; }
public Uri imagePath { get; set; }
public Titles(List<Item> list) : base(list)
{
}
}
public class Item
{
public string Id { get; set; }
public string Text { get; set; }
public string Description { get; set; }
public string Href { get; set; }
public string Time { get; set; }
public string TeamOne { get; set; }
public string ScoreTeamOne { get; set; }
public string ScoreTeamTwo { get; set; }
public string TeamTwo { get; set; }
public string Tip { get; set; }
public Color TipBGColor { get; set; }
}
My problem here is that the five headers are created but items are not created within them and the titles of the headers are not binded.
It is just empty.
Any ideas?
What you need to do is set the IsGroupingEnabled of ListView to true :
<ListView ItemsSource="{Binding DetailedViewModel.sortedItems}" IsGroupingEnabled="True">
The document is here: customizing-list-appearance#grouping
You need to enable grouping in your Listview
<ListView ItemsSource="{Binding DetailedViewModel.sortedItems}" IsGroupingEnabled="True">
Related
I am using Xamarin Forms Collection View, inside this collection view is toolkit expander, When someone clicks the header I have binded a command, inside this command I am trying to populate a list view inside the grid of the expander, see code below:
<CollectionView x:Name="MathList" HeightRequest="320" SelectionChanged="MathList_SelectionChanged">
<CollectionView.ItemTemplate>
<DataTemplate>
<xct:Expander Command="{Binding GetMathSubCatgories}">
<xct:Expander.Header>
<Frame Padding="10" Margin="10" HasShadow="False" BorderColor="LightGray" VerticalOptions="CenterAndExpand">
<StackLayout Orientation="Horizontal">
<Image Source="{Binding icon}" WidthRequest="25" HeightRequest="25"></Image>
<Label Text="{Binding name}" TextColor="{Binding textColor}" FontSize="Large" FontAttributes="Bold" HeightRequest="35" VerticalOptions="CenterAndExpand"></Label>
</StackLayout>
</Frame>
</xct:Expander.Header>
<Grid Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ListView x:Name="SubCatgories" ItemsSource="{Binding subTaskClass}">
<ListView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame Padding="10" Margin="10" HasShadow="False" BorderColor="LightGray" VerticalOptions="CenterAndExpand">
<StackLayout Orientation="Horizontal">
<Label Text="aaa" FontAttributes="Bold" HeightRequest="35" VerticalOptions="CenterAndExpand"></Label>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</xct:Expander>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
But in my code behind when I try to populate the list view like so:
public ICommand GetMathSubCatgories => new Command(() =>
{
Console.Write("Here");
GetSubTasks(taskcategoryid);
});
public async void GetSubTasks(int taskcategory)
{
SubCatgories.ItemsSource = await webService.GetMathSubTasks(taskcategory);
}
It says SubCatgories is not available. How would I populate a list view inside the datacollection.
I have also tried this approach, still nothing:
<CollectionView x:Name="MathList" HeightRequest="320" SelectionChanged="MathList_SelectionChanged">
<CollectionView.ItemTemplate>
<DataTemplate>
<xct:Expander Command="{Binding GetMathSubCatgories}">
<xct:Expander.Header>
<Frame Padding="10" Margin="10" HasShadow="False" BorderColor="LightGray" VerticalOptions="CenterAndExpand">
<StackLayout Orientation="Horizontal">
<Image Source="{Binding icon}" WidthRequest="25" HeightRequest="25"></Image>
<Label Text="{Binding name}" TextColor="{Binding textColor}" FontSize="Large" FontAttributes="Bold" HeightRequest="35" VerticalOptions="CenterAndExpand"></Label>
</StackLayout>
</Frame>
</xct:Expander.Header>
<Grid Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ListView x:Name="SubCatgories" ItemsSource="{Binding subCategories}">
<ListView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame Padding="10" Margin="10" HasShadow="False" BorderColor="LightGray" VerticalOptions="CenterAndExpand">
<StackLayout Orientation="Horizontal">
<Label Text="{Binding name}" FontAttributes="Bold" HeightRequest="35" VerticalOptions="CenterAndExpand"></Label>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</xct:Expander>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Here is the class I am using for the collectionView
public class TaskClass
{
WebServiceClass webService = new WebServiceClass();
List<SubTaskClass> subTasks = new List<SubTaskClass>();
public int taskcategoryid { get; set; }
public string type { get; set; }
public string name { get; set; }
public string icon { get; set; }
public int sortOrder { get; set; }
public string textColor
{
get
{
if (name == "Addition")
{
return "#02cc9d";
}
else if (name == "Subtraction")
{
return "black";
}
else if (name == "Divison")
{
return "#fa5156";
}
else
{
return "#23a0b6";
}
}
}
public List<SubTaskClass> subCategories
{
get
{
GetSubTasks(taskcategoryid);
return subTasks;
}
}
public async void GetSubTasks(int taskcategory)
{
subTasks = await webService.GetMathSubTasks(taskcategory);
}
}
and here is the SubTaskClass:
public class SubTaskClass
{
public int id { get; set; }
public int taskcategory { get; set; }
public string name { get; set; }
}
From your code, I do one sample that you can take a look.
<CollectionView
x:Name="MathList"
ItemsSource="{Binding catgories}"
SelectedItem="{Binding selecteditem}"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<xct:Expander Command="{Binding command1}">
<xct:Expander.Header>
<Frame
Margin="10"
Padding="10"
BorderColor="LightGray"
HasShadow="False"
VerticalOptions="CenterAndExpand">
<StackLayout Orientation="Horizontal">
<Image
HeightRequest="25"
Source="{Binding icon}"
WidthRequest="25" />
<Label
FontAttributes="Bold"
FontSize="Large"
HeightRequest="35"
Text="{Binding name}"
TextColor="{Binding textColor}"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</Frame>
</xct:Expander.Header>
<Grid Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ListView x:Name="SubCatgories" ItemsSource="{Binding subtasks}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Frame
Margin="10"
Padding="10"
BorderColor="LightGray"
HasShadow="False"
VerticalOptions="CenterAndExpand">
<StackLayout Orientation="Horizontal">
<Label
FontAttributes="Bold"
HeightRequest="35"
Text="{Binding name}"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</Frame>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</xct:Expander>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
this.BindingContext = new SubCatgories();
}
}
public class SubCatgories : INotifyPropertyChanged
{
public ObservableCollection<TaskClass> catgories { get; set; }
public ICommand command1 { get; set; }
private TaskClass _selecteditem;
public TaskClass selecteditem
{
get { return _selecteditem; }
set
{
_selecteditem = value;
RaisePropertyChanged("selecteditem");
}
}
public SubCatgories()
{
catgories = new ObservableCollection<TaskClass>()
{
new TaskClass(){icon="favorite.png",name="catgory 1",textColor=Color.Black,subtasks=new ObservableCollection<SubTaskClass>(){
new SubTaskClass(){name="sub class 1"}, new SubTaskClass(){name="sub class 2"}, new SubTaskClass(){name="sub class 3"}
} },
new TaskClass(){icon="check.png",name="catgory 2",textColor=Color.Blue,subtasks=new ObservableCollection<SubTaskClass>(){
new SubTaskClass(){name="sub class 1"}, new SubTaskClass(){name="sub class 2"}, new SubTaskClass(){name="sub class 3"}
} },
new TaskClass(){icon="delete.png",name="catgory 3",textColor=Color.YellowGreen,subtasks=new ObservableCollection<SubTaskClass>(){
new SubTaskClass(){name="sub class 1"}, new SubTaskClass(){name="sub class 2"}, new SubTaskClass(){name="sub class 3"}
} },
new TaskClass(){icon="flag.png",name="catgory 4",textColor=Color.ForestGreen,subtasks=new ObservableCollection<SubTaskClass>(){
new SubTaskClass(){name="sub class 1"}, new SubTaskClass(){name="sub class 2"}, new SubTaskClass(){name="sub class 3"}
} },
};
selecteditem = catgories[0];
command1 = new Command(() => { Console.WriteLine(selecteditem.name); });
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class TaskClass
{
public string icon { get; set; }
public string name { get; set; }
public Color textColor { get; set; }
public ObservableCollection<SubTaskClass> subtasks { get; set; }
}
public class SubTaskClass
{
public int id { get; set; }
public int taskcategory { get; set; }
public string name { get; set; }
}
The screenshot:
Note: Data items in a ListView are called cells, add ViewCell in ListView.
Good morning everyone, I have a sensor model class that, when the state changes, starts a timer that measures random values at intervals. How can I change the measured values on the main form with the same interval?
This is my window xaml markup
<ListBox Width="100" Name="Lst" Grid.Column="0" Grid.Row="1" SelectionChanged="Lst_OnSelectionChanged"/>
<Label Width="244" Style="{StaticResource SideText}" x:Name ="LavalIntervalValue" Grid.Row="1" Grid.Column="1" Margin="215,18,0,344" Height="40"/>
<Label Width="244" Style="{StaticResource SideText}" x:Name ="LabelIdValue" Grid.Row="1" Grid.Column="1" Margin="215,73,0,289" Height="40"/>
<Label Width="244" Style="{StaticResource SideText}" x:Name ="LabelStateValue" Grid.Row="1" Grid.Column="1" Margin="215,130,0,232" Height="40"/>
<Label Width="244" Style="{StaticResource SideText}" x:Name ="LabelMeasuredValue" Grid.Row="1" Grid.Column="1" Margin="215,188,0,174" Height="40" />
<Label Width="186" Style="{StaticResource MainText}" Content="Interval" x:Name ="LabelInterval" Grid.Row="1" Grid.Column="1" Margin="11,18,663,344" Height="40"/>
<Label Width="187" Style="{StaticResource MainText}" Content="Id" x:Name ="LabelId" Grid.Row="1" Grid.Column="1" Margin="10,73,663,289" Height="40"/>
<Label Width="186" Style="{StaticResource MainText}" Content="State" x:Name ="LabelState" Grid.Row="1" Grid.Column="1" Margin="11,130,663,233" Height="39"/>
<Label Width="186" Style="{StaticResource MainText}" Content="Measured Value" x:Name ="LabelMeasured" Grid.Row="1" Grid.Column="1" Margin="11,188,663,175" Height="39"/>
This is my model
public class Sensor:IObservable
{
private int _measuredValue;
private List<IObserver> _observers = new List<IObserver>();
private IMeasuringState _state = new SimpleState();
public Sensor(int measuringInterval, SensorType sensorType, int uniqueId)
{
MeasuringInterval = measuringInterval;
SensorType = sensorType;
UniqueId = uniqueId;
}
[JsonIgnore]
public IMeasuringState MeasuringState
{
get => _state;
set
{
if (value!=null)
{
_state = value;
}
NotifyObservers();
}
}
public int UniqueId { get; }
public int MeasuredValue
{
get => _measuredValue;
set
{
_measuredValue = value;
NotifyObservers();
}
}
public SensorType SensorType { get; }
public int MeasuringInterval { get; }
public void ChangeState()
{
MeasuringState.Handle(this);
MeasuringState.StartMeasure(this);
}
}
Calibration state
public void StartMeasure(Sensor sensor)
{
_calibrationValue = 0;
_timer = new Timer(SetCalibration, sensor, 0, 1000);
}
public void Handle(Sensor sensor)
{
_timer.Dispose();
sensor.MeasuringState = new WorkState();
}
private void SetCalibration(object obj)
{
var sensor = obj as Sensor;
sensor.MeasuredValue = ++_calibrationValue;
}
This is my interface that I implemented in my main window
In property I set my label content value with presenter.
public interface IMainWindowView
{
List<string> SensorsType { get; set; }
int SelectedSensor { get; set; }
int MeasuredValue { get; set; }
string State { get; set; }
int Id { get; set; }
int MeasuringInterval { get; set; }
event EventHandler<EventArgs> OpenFile;
event EventHandler<StateEventArgs> DeleteSensorById;
event EventHandler<EventArgs> SaveFile;
event EventHandler<EventArgs> SelectedItem;
event EventHandler<StateEventArgs> ChangeStateSensor;
event EventHandler<EventArgs> OpenAddWindow;
void ShowWarning(string message);
}
I've got some issues with grouping my List Views.
When I isgroupingenabled = "true" my List only shows the groupDisplayBinding name.
I've read and tried so many things and wasn't able to apply them to my project I need your help now.
I've seen I need to put an Observablecollection but don't know where and how to do it.
My Model
public class League
{
public string name { get; set; }
public string country { get; set; }
public string logo { get; set; }
public string flag { get; set; }
}
public class HomeTeam
{
public int team_id { get; set; }
public string team_name { get; set; }
public string logo { get; set; }
}
public class AwayTeam
{
public int team_id { get; set; }
public string team_name { get; set; }
public string logo { get; set; }
}
public class Score
{
public string halftime { get; set; }
public string fulltime { get; set; }
public string extratime { get; set; }
public string penalty { get; set; }
}
public class Fixture
{
public int fixture_id { get; set; }
public int league_id { get; set; }
public League league { get; set; }
public DateTime event_date { get; set; }
public int event_timestamp { get; set; }
public int? firstHalfStart { get; set; }
public int? secondHalfStart { get; set; }
public string round { get; set; }
public string status { get; set; }
public string statusShort { get; set; }
public int elapsed { get; set; }
public string venue { get; set; }
public string referee { get; set; }
public HomeTeam homeTeam { get; set; }
public AwayTeam awayTeam { get; set; }
public int? goalsHomeTeam { get; set; }
public int? goalsAwayTeam { get; set; }
public Score score { get; set; }
}
public class Api
{
public int results { get; set; }
public List<Fixture> Fixtures { get; set; }
}
public class RootFixtures
{
public Api api { get; set; }
}
My JSON : (Part of it)
{"api": {
"results": 162,
"fixtures": [
{
"fixture_id": 234670,
"league_id": 900,
"league": {
"name": "Division 1",
"country": "Saudi-Arabia",
"logo": null,
"flag": "https://media.api-sports.io/flags/sa.svg"
},
"event_date": "2020-03-10T00:00:00+00:00",
"event_timestamp": 1583798400,
"firstHalfStart": null,
"secondHalfStart": null,
"round": "Regular Season - 28",
"status": "Match Postponed",
"statusShort": "PST",
"elapsed": 0,
"venue": "Prince Saud bin Jalawi Stadium (al-Khobar (Khobar))",
"referee": null,
"homeTeam": {
"team_id": 2933,
"team_name": "Al-Qadisiyah FC",
"logo": "https://media.api-sports.io/teams/2933.png"
},
"awayTeam": {
"team_id": 2928,
"team_name": "Al Khaleej Saihat",
"logo": "https://media.api-sports.io/teams/2928.png"
},
"goalsHomeTeam": null,
"goalsAwayTeam": null,
"score": {
"halftime": null,
"fulltime": null,
"extratime": null,
"penalty": null
}
}
]
}
}
ListMatchPage :
public partial class ListMatchs : ContentPage
{
string JsonLeagues = "The Json Below"
public ListMatchs()
{
InitializeComponent();
var Leagues = JsonConvert.DeserializeObject<RootFixtures>(JsonLeagues);
LeaguesList.ItemsSource = Leagues.api.Fixtures;
}
}
I'm new at dev and here I Hope my english wasn't too bad.
edit :
MyXAML :
<ContentPage.Content>
<StackLayout>
<Label Text="Futurs matchs" HorizontalTextAlignment="Center" />
<ListView x:Name="LeaguesList" GroupDisplayBinding="{Binding Path=League.name}"
GroupShortNameBinding="{Binding Path=League.name}"
IsGroupingEnabled="True" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Height="30">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Aspect="AspectFit" Source="{Binding Path=homeTeam.logo}" />
<Label Grid.Column="1" VerticalOptions="CenterAndExpand" HorizontalTextAlignment="Center" TextColor="Black" FontSize="15" FontAttributes="Bold" Text="{Binding Path=homeTeam.team_name}" HorizontalOptions="CenterAndExpand"/>
<Label Grid.Column="2" VerticalOptions="CenterAndExpand" HorizontalTextAlignment="Center" TextColor="Black" FontSize="15" FontAttributes="Bold" Text="{Binding Path=awayTeam.team_name}" HorizontalOptions="CenterAndExpand"/>
<Image Grid.Column="3" Aspect="AspectFit" Source="{Binding Path=awayTeam.logo}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
#JackHUA here is what I did :
XAML.CS :
ObservableCollection<groupedfix> FixturesCollection = new ObservableCollection<groupedfix>();
public ListMatchs()
{
InitializeComponent();
var Leagues = JsonConvert.DeserializeObject<RootFixtures>(JsonLeagues);
foreach (var match in Leagues.api.Fixtures)
{
int fixtureid = match.fixture_id;
DateTime fixturedate = match.event_date;
int FixtureLeagueid = match.league_id;
string FixtureLeague = match.league.name;
string FixtureLeaguelogo = match.league.logo;
string Hometeamname = match.homeTeam.team_name;
string Hometeamlogo = match.homeTeam.logo;
string Awayteamname = match.awayTeam.team_name;
string Awayteamlogo = match.awayTeam.logo;
HomeTeam HOMETEAM = new HomeTeam() { team_name = Hometeamname, logo = Hometeamlogo };
AwayTeam AWAYTEAM = new AwayTeam() { team_name = Awayteamname, logo = Awayteamlogo };
League LEAGUE = new League() { logo = FixtureLeaguelogo, name = FixtureLeague };
Fixture MATCH = new Fixture() { fixture_id = fixtureid, event_date = fixturedate, league_id = FixtureLeagueid, league = LEAGUE, homeTeam = HOMETEAM, awayTeam = AWAYTEAM };
groupedfix GROUPEDFIX = new groupedfix(FixtureLeague) { MATCH };
FixturesCollection.Add(GROUPEDFIX);
}
LeaguesList.ItemsSource = FixturesCollection;
}
public class groupedfix : List<Fixture>
{
public string FixtureLeague { get; set; }
public groupedfix(string Name )
{
FixtureLeague = Name;
}
}
XAML :
<ContentPage.Content>
<StackLayout>
<Label Text="Futurs matchs" HorizontalTextAlignment="Center" />
<ListView x:Name="LeaguesList" GroupDisplayBinding="{Binding FixtureLeague}"
IsGroupingEnabled="True" HasUnevenRows="True" ItemTapped="Newgameclick">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Height="30">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Aspect="AspectFit" Source="{Binding Path=homeTeam.logo}"/>
<Label Grid.Column="1" VerticalOptions="CenterAndExpand" HorizontalTextAlignment="Center" TextColor="Black" FontSize="15" FontAttributes="Bold" Text="{Binding Path=homeTeam.team_name}" HorizontalOptions="CenterAndExpand"/>
<Label Grid.Column="2" VerticalOptions="CenterAndExpand" HorizontalTextAlignment="Center" TextColor="Black" FontSize="15" FontAttributes="Bold" Text="{Binding Path=awayTeam.team_name}" HorizontalOptions="CenterAndExpand"/>
<Image Grid.Column="3" Aspect="AspectFit" Source="{Binding Path=awayTeam.logo}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
The image result :
See the pic
But when I change
LeaguesList.ItemsSource = FixturesCollection;
in
LeaguesList.ItemsSource = FixturesCollection.GroupBy(F => F.FixtureLeague);
I get this : See the pic
With error :
[0:] Binding:'FixtureLeague' property not found on 'System.Linq.Grouping`2[System.String,BeastTIPS.Pages.ListMatchs+groupedfix]'...
[0:] Binding: 'homeTeam' property not found on 'BeastTIPS.Pages.ListMatchs+groupedfix'...
[0:] Binding: 'awayTeam' property not found on 'BeastTIPS.Pages.ListMatchs+groupedfix'...
The List is groupedby but my Binding are not found
I can't find what property to Bind.
The model you added to the ItemsSource should in a right format as the document mentioned, I wrote a example for you and you can check the code:
public partial class MainPage : ContentPage
{
ObservableCollection<myModel> FixtureCollection = new ObservableCollection<myModel>();
public MainPage()
{
InitializeComponent();
League LeagueOne = new League() { name = "one" };
League LeagueTwo = new League() { name = "two" };
League LeagueThree = new League() { name = "three" };
HomeTeam HomeTeamOne = new HomeTeam() { team_name = "HomeTeamOne" };
HomeTeam HomeTeamTwo = new HomeTeam() { team_name = "HomeTeamTwo" };
HomeTeam HomeTeamThree = new HomeTeam() { team_name = "HomeTeamThree" };
AwayTeam AwayTeamOne = new AwayTeam() { team_name = "AwayTeamOne" };
AwayTeam AwayTeamTwo = new AwayTeam() { team_name = "AwayTeamTwo" };
AwayTeam AwayTeamThree = new AwayTeam() { team_name = "AwayTeamThree" };
Fixture FixtureOne = new Fixture() { league = LeagueOne, homeTeam = HomeTeamOne, awayTeam = AwayTeamOne};
Fixture FixtureTwo = new Fixture() { league = LeagueTwo, homeTeam = HomeTeamTwo, awayTeam = AwayTeamTwo };
Fixture FixtureThree = new Fixture() { league = LeagueThree, homeTeam = HomeTeamThree, awayTeam = AwayTeamThree };
myModel myModelOne = new myModel(FixtureOne.league.name) { FixtureOne };
myModel myModelTwo = new myModel(FixtureTwo.league.name) { FixtureTwo };
myModel myModelThree = new myModel(FixtureThree.league.name) {FixtureThree };
FixtureCollection.Add(myModelOne);
FixtureCollection.Add(myModelTwo);
FixtureCollection.Add(myModelThree);
LeaguesList.ItemsSource = FixtureCollection;
BindingContext = this;
}
}
public class myModel : List<Fixture>
{
public string name { get; set; }
public myModel( string Name) {
name = Name;
}
}
And in code behind:
<StackLayout>
<Label Text="Futurs matchs" HorizontalTextAlignment="Center" />
<ListView x:Name="LeaguesList"
GroupDisplayBinding="{Binding name}"
GroupShortNameBinding="{Binding name}"
IsGroupingEnabled="True" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Height="30">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Aspect="AspectFit" Source="{Binding Path=homeTeam.logo}" />
<Label Grid.Column="1" VerticalOptions="CenterAndExpand" HorizontalTextAlignment="Center" TextColor="Black" FontSize="15" FontAttributes="Bold" Text="{Binding Path=homeTeam.team_name}" HorizontalOptions="CenterAndExpand"/>
<Label Grid.Column="2" VerticalOptions="CenterAndExpand" HorizontalTextAlignment="Center" TextColor="Black" FontSize="15" FontAttributes="Bold" Text="{Binding Path=awayTeam.team_name}" HorizontalOptions="CenterAndExpand"/>
<Image Grid.Column="3" Aspect="AspectFit" Source="{Binding Path=awayTeam.logo}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
I also uploaded my sample project here and feel free to ask me any question.
Update:
I think what you really need is OrderBy not GroupBy:
LeaguesList.ItemsSource = FixturesCollection.OrderBy(f => f.FixtureLeague).ToList();
When you use GroupBy, you can set a breakpoint right there to check the LeaguesList.ItemsSource, you will find the structure has been change, the count of LeaguesList.ItemsSource becomes 56.
There is another problem in your xaml, the GroupDisplayBinding should bind to FixtureLeague not name:
<ListView x:Name="LeaguesList" GroupDisplayBinding="{Binding FixtureLeague}"
I am using Xamarin Forms and I have created a collection view, I am getting the data from an api after getting the device location, my question is how can I reload the collectionview? Here is my code:
public partial class HomePage : ContentPage
{
APIClass aPIClass = new APIClass();
public HomePage()
{
InitializeComponent();
getLocation();
}
public async void getLocation()
{
try
{
var location = await Geolocation.GetLastKnownLocationAsync();
if (location != null)
{
HomeClass places = aPIClass.getUserPlace(location.Latitude.ToString(), location.Longitude.ToString());
HomeCollection.ItemsSource = places.results;
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}");
}
}
catch(Exception e)
{
Console.WriteLine(e.Message.ToString());
}
}
}
And my view:
<CollectionView x:Name="HomeCollection">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="150" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<BoxView Color="White" Grid.Column="1" Grid.RowSpan="2"/>
<ContentView Padding="10" Grid.Row="0" Grid.Column="1">
<Image Grid.Row="0" Grid.Column="1" Source="{Binding photos[0].name}" Aspect="AspectFill" />
</ContentView>
<ContentView Padding="10" Grid.Row="1" Grid.Column="1">
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding name}" />
</ContentView>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Classes involved:
public class HomeClass
{
public List<PlacesClass> results { get; set; }
}
public class PlacesClass
{
public string name { get; set; }
public List<PlacesImageClass> photos { get; set; }
}
public class PlacesImageClass
{
public int height { get; set; }
public List<string> html_attributions { get; set; }
public string photo_reference { get; set; }
public int width { get; set; }
public string name { get; set; }
}
I have a list view that displays a ladder of points on a sports team and am trying to only show the top 5 players. Is there anyway that this can be in XAML?
Thanks,
Ryan
EDIT: Here is my code
XAML:
<?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="MIApp.PlayerPage">
<ContentPage.Content>
<StackLayout Margin="20,0,0,0" Orientation="Vertical" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
<Label Text="Player Info" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"/>
<Grid MinimumHeightRequest="200" RowSpacing="10" Padding="0">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition/>
<RowDefinition Height="50"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Text="Goal Leaders" Grid.Row="0" Margin="0"/>
<ListView x:Name="GoalListView" Grid.Row="1">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" Margin="0,0,0,0" Spacing="0" VerticalOptions="Center">
<Label Text="{Binding StrFullName}" HorizontalOptions="Start" VerticalTextAlignment="Center"/>
<Label Text="{Binding IntGoals}" HorizontalOptions="End" VerticalTextAlignment="Center"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Label Text="Point Leaders" Grid.Row="2" Margin="0"/>
<ListView x:Name="PointListView" HasUnevenRows="true" Grid.Row="3" Margin="0,0,0,0">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" Margin="0,0,0,0" Spacing="0" VerticalOptions="Center">
<Label Text="{Binding StrFullName}" HorizontalOptions="Start" VerticalTextAlignment="Center"/>
<Label Text="{Binding IntPoints}" HorizontalOptions="End" VerticalTextAlignment="Center"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Code Behind:
public partial class PlayerPage : ContentPage
{
public PlayerPage()
{
InitializeComponent();
}
protected async override void OnAppearing()
{
base.OnAppearing();
HttpClient client = new HttpClient();
string urlGoals = "https://melbourneicewebapi.azurewebsites.net/api/Player_Info/GetPlayer_Info?playerInfo=goals";
string urlPoints = "https://melbourneicewebapi.azurewebsites.net/api/Player_Info/GetPlayer_Info?playerInfo=points";
var responseGoals = await client.GetAsync(urlGoals);
var responsePoints = await client.GetAsync(urlPoints);
if (responsePoints.IsSuccessStatusCode)
{
string resGoals = "";
using (HttpContent contentGoals = responseGoals.Content)
{
Task<string> resultGoals = contentGoals.ReadAsStringAsync();
resGoals = resultGoals.Result;
var GoalsList = Players.PlayersItems.FromJson(resGoals);
GoalListView.ItemsSource = GoalsList;
}
string resPoints = "";
using (HttpContent contentPoints = responsePoints.Content)
{
Task<string> resultPoints = contentPoints.ReadAsStringAsync();
resPoints = resultPoints.Result;
var PointsList = Players.PlayersItems.FromJson(resPoints);
PointListView.ItemsSource = PointsList;
}
}
else
{
await DisplayAlert("Connection Error", "Please Connect to the internet and try again", "Ok");
}
}
}
Players Class where objects are created from JSON string and added into a list:
public class Players
{
public partial class PlayersItems
{
[JsonProperty("$id")]
public long Id { get; set; }
[JsonProperty("intPlayerID")]
public int IntPlayerId { get; set; }
[JsonProperty("strFirstName")]
public string StrFirstName { get; set; }
[JsonProperty("strSurname")]
public string StrSurname { get; set; }
[JsonProperty("intGamesPlayed")]
public int IntGamesPlayed { get; set; }
[JsonProperty("strPosition")]
public string StrPosition { get; set; }
[JsonProperty("intPlayerNumber")]
public int IntPlayerNumber { get; set; }
[JsonProperty("intGoals")]
public int IntGoals { get; set; }
[JsonProperty("intAssists")]
public int IntAssists { get; set; }
[JsonProperty("intPoints")]
public int IntPoints { get; set; }
public string StrFullName {
get
{
return StrFirstName.Trim() + " " + StrSurname.Trim();
}
}
}
public partial class PlayersItems
{
public static List<PlayersItems> FromJson(string json)
{
return JsonConvert.DeserializeObject<List<PlayersItems>>(json);
}
}
}
So what I am essentially doing is accessing an API that gives me two JSON Strings of all the data entries in the Players Table,One that is sorted by highest points, the other by highest goals, it is then converted into a list of objects from the Players Class, and then set to the appropriate List View.
use LINQ to select the top X scores before assigning them to ItemsSource. I'm not aware of any way to filter the data directly in XAML
var PointsList = Players.PlayersItems.FromJson(resPoints);
var topPoints = PointsList.OrderByDescending(x => x.PointsInt).Take(5).ToList();
PointListView.ItemsSource = topPoints;