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; }
}
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.
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 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">
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;
I have the following requirements:
Show TreeView of items
Show Details of selected item in TreeView.
A dialog to edit the selected item.
I've implemented these requirements but the third doesn't do what it is supposed to do so I'm stuck.
What I want it to do :
The edit dialog should be able to edit an item. This isn't a TreeViewItem but an instance of one of my classes.
Save the edits - A button that will just close the dialog.
Discard the edits - A button to reset the fields changed in the item and close dialog.
The second requirement does not work. If I edit a field and hit Cancel, the item details panel still shows the edits. I have debugged but I find that the underlying item is unchanged - however the item is displayed with the changed values.
Code:
Item class (Category)
public class Category
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual Unit Unit { get; set; }
public virtual List<Category> ChildCategories { get; set; }
public virtual Category ParentCategory { get; set; }
public virtual bool IsMainCategory { get; set; }
public Category()
{
ChildCategories = new List<Category>();
}
public virtual void AddChild(Category child)
{
ChildCategories.Add(child);
child.ParentCategory = this;
}
}
Item (Category) Details are shown in a label:
<DataTemplate DataType="{x:Type local:Category}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*" SharedSizeGroup="a" />
<ColumnDefinition Width="6*" SharedSizeGroup="b" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<TextBlock Text="Name" Grid.Column="0" Grid.Row="0" Padding="5"/>
<TextBlock Text="{Binding Path=Name}" Grid.Column="1" Grid.Row="0" Padding="5"/>
<TextBlock Text="Description" Grid.Column="0" Grid.Row="1" Padding="5"/>
<TextBlock Text="{Binding Path=Description}" Grid.Column="1" Grid.Row="1" Padding="5"/>
</Grid>
</DataTemplate>
Event handler for Edit item in Main Window :
private void EditCategory(object sender, RoutedEventArgs e)
{
Category ctg = _tree.SelectedItem as Category;
if (ctg != null)
{
CategoryDefineWindow cdw = new CategoryDefineWindow();
cdw.CategoryObject = ctg;
cdw.ShowDialog();
}
}
Item editor window xaml:
<Window x:Class="BSRCat.View.CategoryDefineWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="150" Width="500">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" SharedSizeGroup="a" />
<ColumnDefinition Width="7*" SharedSizeGroup="b" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<TextBlock Text="Name" Grid.Column="0" Grid.Row="0" Padding="5"/>
<TextBox Text="{Binding Path=CategoryObject.Name, RelativeSource={RelativeSource AncestorType=Window}}" Grid.Column="1" Grid.Row="0" Padding="5"/>
<TextBlock Text="Description" Grid.Column="0" Grid.Row="1" Padding="5"/>
<TextBox Text="{Binding Path=CategoryObject.Description, RelativeSource={RelativeSource AncestorType=Window}}" Grid.Column="1" Grid.Row="1" Padding="5"/>
<StackPanel Orientation="Horizontal" Grid.Row="2" Grid.ColumnSpan="2" HorizontalAlignment="Right">
<Button Content="Ok" Margin="5" Height="20" Width="30" Click="Confirmed"/>
<Button Content="Cancel" Margin="5" Height="20" Width="50" Click="Cancelled"/>
</StackPanel>
</Grid>
</Window>
Item editor window code behind :
public partial class CategoryDefineWindow : Window
{
public Category CategoryObject
{
get
{
return _category;
}
set
{
_category = value;
_initial = new Category() { Name = value.Name, Description = value.Description };
}
}
private Category _category;
private Category _initial;
public CategoryDefineWindow()
{
InitializeComponent();
}
private void Confirmed(object sender, RoutedEventArgs e)
{
Close();
}
private void Cancelled(object sender, RoutedEventArgs e)
{
_category.Name = _initial.Name;
_category.Description = _initial.Description;
Close();
}
}
I've debugged the CategoryDefineWindow.Cancelled method and the _category object is reset correctly. I can't find where it goes wrong.
Category class should be implemented INotifyPropertyChanged interface. WPF will be notified once the value of properties have changed.
public class Category : INotifyPropertyChanged
{
private string _Name;
private string _Description;
public virtual int Id { get; set; }
public virtual string Name
{
get
{
return _Name;
}
set
{
if (_Name == value)
return;
_Name = value;
NotifyPropertyChanged("Name");
}
}
public virtual string Description
{
get
{
return _Description;
}
set
{
if (_Description == value)
return;
_Description = value;
NotifyPropertyChanged("Description");
}
}
public virtual Unit Unit { get; set; }
public virtual List<Category> ChildCategories { get; set; }
public virtual Category ParentCategory { get; set; }
public virtual bool IsMainCategory { get; set; }
public Category()
{
ChildCategories = new List<Category>();
}
public virtual void AddChild(Category child)
{
ChildCategories.Add(child);
child.ParentCategory = this;
}
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}