How can I display JSON array to ListView, I'm confused can somebody help me?
I tried these code and it's not working.
my JSON array
{"table":[
{"table_no":"1","order_status":"served"},
{"table_no":"2","order_status":"pending"},
{"table_no":"3","order_status":"served"},
{"table_no":"4","order_status":"served"},
{"table_no":"8","order_status":"served"},
{"table_no":"10","order_status":"served"},
{"table_no":"11","order_status":"served"},
{"table_no":"12","order_status":"served"},
{"table_no":"14","order_status":"pending"},
{"table_no":"16","order_status":"served"}]}
OrderStat.cs (How do i bind this or how do i deserialize it?)
public class OrderStat
{
public string table_no { get; set; }
public string order_status { get; set; }
}
public class RootObject
{
public List<OrderStat> table { get; set; }
}
OrderStatus.xaml
<ListView x:Name="selectOrd" RowHeight="50" SeparatorColor="White"
HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<StackLayout Orientation="Horizontal" >
<StackLayout Orientation="Horizontal" VerticalOptions="Center">
<Image Source="table.png" Scale="1"/>
<Label Text="{Binding table_no,StringFormat=' Table no.{0:F0}'}" Font="30" TextColor="White" />
</StackLayout>
<StackLayout HorizontalOptions="FillAndExpand" x:Name="BG" VerticalOptions="Center" >
<Label Text="{Binding order_status}" Font="50" TextColor="White" FontAttributes="Bold" HorizontalTextAlignment="Center"/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
OrderStatus.xaml.cs
private async void GetStat()
{
HttpClient client = new HttpClient();
var response = await client.GetStringAsync("http://ropenrom2-001-site1.etempurl.com/Restserver/index.php/customer/view_table_orders");
var stat = JsonConvert.DeserializeObject<List<RootObject>>(response);
selectOrd.ItemsSource = stat;
}
This is the right way to show the json in ListView. I've also updated your Xaml too. I just removed the white text color and x:Name from your ListView.
Xaml
<ListView x:Name="selectOrd" RowHeight="50" SeparatorColor="White"
HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" >
<StackLayout Orientation="Horizontal" VerticalOptions="Center">
<Image Source="table.png" Scale="1"/>
<Label Text="{Binding table_no,StringFormat='Table no.{0:F0}'}" Font="30" />
</StackLayout>
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="Center" >
<Label Text="{Binding order_status}" Font="50" FontAttributes="Bold" HorizontalTextAlignment="Center"/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
OrderStat Class
[DataContract]
public class OrderStat
{
[DataMember]
public string table_no { get; set; }
[DataMember]
public string order_status { get; set; }
}
[DataContract]
public class RootObject
{
[DataMember]
public List<OrderStat> table { get; set; }
}
MainPage.xaml.cs
public MainPage()
{
InitializeComponent();
GetStat();
}
private async void GetStat()
{
HttpClient client = new HttpClient();
var response = await client.GetAsync("http://ropenrom2-001-site1.etempurl.com/Restserver/index.php/customer/view_table_orders");
var result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(RootObject));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject)serializer.ReadObject(ms);
selectOrd.ItemsSource = data.table;
}
Hi Actual you do not define the select order and the also the objects
retrieve from the JSON should be OrderStat .below is the edited code
<StackLayout BackgroundColor="White">
<ListView x:Name="ListView1" RowHeight="60">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" Padding="8,0,8,0">
<Label Text="{Binding ArticleTitle}" TextColor="#000" FontSize="14" LineBreakMode="TailTruncation" />
<Label Text="{Binding description}" TextColor="#000" LineBreakMode="TailTruncation" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
private async void GetStat()
{
HttpClient client = new HttpClient();
var response = await client.GetStringAsync("http://ropenrom2-001- site1.etempurl.com/Restserver/index.php/customer/view_table_orders");
var stat = JsonConvert.DeserializeObject<List<OrderStat>>(response);
ListView1.ItemsSource = stat;
// selectOrd.ItemsSource = stat;
}
Related
So I have a xamarin forms app that currently only implemented for android. I am attempting to implement a tap event. When tapped though this never hits the command in the ViewModel. I'm not sure if I have something the matter with my code or I am just implementing it wrong.
ViewModel Code:
private RelayCommand<object> _OnClickableLabel;
public RelayCommand<object> OnClickableLabel
{
get { return _OnClickableLabel ?? (_OnClickableLabel = new RelayCommand<object>((currentObject) => Test(currentObject))); }
}
private void Test(object currentObject)
{
Application.Current.MainPage.DisplayAlert("Alert", "were going down cap", "OK");
}
Page Xaml:
<ListView Grid.Row="1" ItemsSource="{Binding Notifications}" RowHeight="100">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" BackgroundColor="{Binding BackgroundColor}">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding OnClickableLabel }" />
</StackLayout.GestureRecognizers>
<Label FontSize="Large" Text="{Binding Title}"></Label>
<Label FontSize="Small" Text="{Binding Text}"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have tested it using a method in the page's cs code and that works fine but it has to be implemented in the ViewModel because it affects that data.
From your description, you want to add a tap gesture recognizer in ListView, and want to pass ListView current row data to TapGestureRecognizer event, am I right?
If yes, as Jason's opinion, you need to take a look Xamarin.Forms Relative Bindings firstly,name ListView as listview1, then take a look the following code:
<ListView
x:Name="listview1"
Grid.Row="1"
ItemsSource="{Binding Notifications}"
RowHeight="100">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="{Binding BackgroundColor}" Orientation="Vertical">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BindingContext.OnClickableLabel, Source={x:Reference listview1}}" CommandParameter="{Binding .}" />
</StackLayout.GestureRecognizers>
<Label FontSize="Large" Text="{Binding Title}" />
<Label FontSize="Small" Text="{Binding Text}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
public partial class Page16 : ContentPage
{
public ObservableCollection<Notclass> Notifications { get; set; }
public ICommand OnClickableLabel { get; set; }
public Page16()
{
InitializeComponent();
Notifications = new ObservableCollection<Notclass>()
{
new Notclass(){Title="title 1",Text="notification 1"},
new Notclass(){Title="title 2",Text="notification 2"},
new Notclass(){Title="title 3",Text="notification 3"},
new Notclass(){Title="title 4",Text="notification 4"},
new Notclass(){Title="title 5",Text="notification 5"}
};
OnClickableLabel = new Command(n=> {
var vm = (Notclass)n;
Application.Current.MainPage.DisplayAlert("Alert",vm.Title , "OK");
});
this.BindingContext = this;
}
}
public class Notclass
{
public string Title { get; set; }
public string Text { get; set; }
public Color BackgroundColor { get; set; } = Color.White;
}
I am having issues with displaying data, I can see my data FieldValue and FieldDescriptor in the List property however I still see in output that:
Binding: 'Results' property not found on 'ViewModel.ResultPageViewModel', target property: 'Xamarin.Forms.ListView.ItemsSource'
I can't see any data FieldVisualData in the horizontal list view even thought I can see them in the view model adding to detail and the command also can't be found.
Binding: 'EditTextCommand' property not found on 'Model.DocumentData', target property: 'Xamarin.Forms.TapGestureRecognizer.Command'
Maybe you see something that I am missing?
<StackLayout Spacing="0">
<!--Pictures-->
<StackLayout VerticalOptions="Start" Spacing="0" >
<controls:HorizontalScrollList VerticalOptions="Start" HeightRequest="300" x:Name="carouselView" ItemsSource="{Binding Results, Mode=TwoWay}">
<controls:HorizontalScrollList.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Results.FieldVisualData}"
Margin="5">
<!--<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding HandlePreviewTapped, Source={x:Reference vm}}"
CommandParameter="{Binding}"/>
</Image.GestureRecognizers>-->
</Image>
</DataTemplate>
</controls:HorizontalScrollList.ItemTemplate>
</controls:HorizontalScrollList>
</StackLayout>
<StackLayout VerticalOptions="Start" BackgroundColor="{DynamicResource SeparatorLineColor}" Spacing="10">
<!--DocumentData-->
<Label Grid.Row="0" HorizontalOptions="CenterAndExpand" Text="Občanský průkaz" VerticalOptions="End" ></Label>
<StackLayout BackgroundColor="{DynamicResource PageBackgroundColor}" VerticalOptions="FillAndExpand">
<ListView x:Name="list" BackgroundColor="{DynamicResource PageBackgroundColor}"
HasUnevenRows="True"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
VerticalScrollBarVisibility="Never"
CachingStrategy="RecycleElement"
ItemsSource="{Binding Results, Mode=TwoWay}"
SeparatorVisibility="Default"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid BackgroundColor="{DynamicResource PageBackgroundColor}" Padding="10" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="15*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="12*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="1" Padding="0" Text ="{Binding FieldDescriptor}" Style="{StaticResource SubLabelBlackStyle}" HorizontalOptions="Start" BackgroundColor="{DynamicResource PageBackgroundColor}" HorizontalTextAlignment="Start"/>
<Label Grid.Column="3" Padding="0" Text="{Binding FieldValue}" FontSize="Small" TextColor="#6781a3" BackgroundColor="{DynamicResource PageBackgroundColor}" HorizontalOptions="Start" HorizontalTextAlignment="Start">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding EditTextCommand}" CommandParameter="{Binding FieldValue}" />
</Label.GestureRecognizers>
</Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</StackLayout>
public partial class ResultPage : ContentPage
{
public ResultPage(IEnumerable<DocumentData> data)
{
InitializeComponent();
BindingContext = new ResultPageViewModel(data);
//carouselView.ItemsSource = data;
// list.ItemsSource = data;
}
}
public class ResultPageViewModel : BaseViewModel
{
public ObservableCollection<DocumentData> Results { get; } = new ObservableCollection<DocumentData>();
public ICommand EditTextCommand { get; }
object param = "";
public ResultPageViewModel(IEnumerable<DocumentData> data)
{
EditTextCommand = new Command(async () => await EditTextAsync(param));
Load(data);
}
public void Load(IEnumerable<DocumentData> data)
{
foreach (var result in data)
{
var detail = new DocumentData()
{
FieldVisualData = result.FieldVisualData,
FieldDescriptor = result.FieldDescriptor,
FieldValue = result.FieldValue,
};
Results.Add(detail);
}
}
public async Task EditTextAsync(object param)
{
PromptResult pResult = await UserDialogs.Instance.PromptAsync(new PromptConfig
{
InputType = InputType.Password,
Text = param.ToString(),
Title = Resources.AppResources.Password_lbl,
});
}
}
public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create(
"ItemTemplate",
typeof(DataTemplate),
typeof(HorizontalScrollList),
null,
propertyChanged: (bindable, value, newValue) => ((HorizontalScrollList)bindable).Populate());
public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(
"ItemsSource",
typeof(IEnumerable),
typeof(HorizontalScrollList),
null,
BindingMode.OneWay,
propertyChanged: (bindable, value, newValue) =>
{
var obs = value as INotifyCollectionChanged;
var self = (HorizontalScrollList)bindable;
if (obs != null)
obs.CollectionChanged -= self.HandleItemChanged;
self.Populate();
obs = newValue as INotifyCollectionChanged;
if (obs != null)
obs.CollectionChanged += self.HandleItemChanged;
});
public IEnumerable ItemsSource
{
get => (IEnumerable)this.GetValue(ItemsSourceProperty);
set => this.SetValue(ItemsSourceProperty, value);
}
public DataTemplate ItemTemplate
{
get => (DataTemplate)this.GetValue(ItemTemplateProperty);
set => this.SetValue(ItemTemplateProperty, value);
}
private bool willUpdate = true;
private void HandleItemChanged(object sender, NotifyCollectionChangedEventArgs eventArgs)
{
if (!willUpdate)
{
willUpdate = true;
Device.BeginInvokeOnMainThread(Populate);
}
}
public HorizontalScrollList()
{
this.Orientation = ScrollOrientation.Horizontal;
}
private void Populate()
{
willUpdate = false;
Content = null;
if (ItemsSource == null || ItemTemplate == null)
{
return;
}
var list = new StackLayout { Orientation = StackOrientation.Horizontal };
foreach (var viewModel in ItemsSource)
{
var content = ItemTemplate.CreateContent();
if (!(content is View) && !(content is ViewCell))
{
throw new Exception($"Invalid visual object {nameof(content)}");
}
var view = content is View ? content as View : ((ViewCell)content).View;
view.BindingContext = viewModel;
list.Children.Add(view);
}
if (list.Children.Count == 0)
{
list.Padding = 20;
list.Children.Add(new Label
{
WidthRequest = (list as VisualElement).Width - 30,
HorizontalOptions = new LayoutOptions(LayoutAlignment.Fill, true),
VerticalOptions = new LayoutOptions(LayoutAlignment.Fill, true),
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
FontSize = 15,
});
}
Content = list;
}
Do you want to acheve the result like following GIF?
I do not which style or backgroundcolor that you setted, I set it with static background color.
Here is my editted layout.controls:HorizontalScrollList is a picture, so I comment it.
I change the Command in the TapGestureRecognizer
<StackLayout Spacing="0">
<!--Pictures-->
<StackLayout VerticalOptions="Start" Spacing="0" >
<!--<controls:HorizontalScrollList VerticalOptions="Start" HeightRequest="300" x:Name="carouselView" ItemsSource="{Binding Results, Mode=TwoWay}">
<controls:HorizontalScrollList.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Results.FieldVisualData}"
Margin="5">
--><!--<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding HandlePreviewTapped, Source={x:Reference vm}}"
CommandParameter="{Binding}"/>
</Image.GestureRecognizers>--><!--
</Image>
</DataTemplate>
</controls:HorizontalScrollList.ItemTemplate>
</controls:HorizontalScrollList>-->
</StackLayout>
<StackLayout VerticalOptions="Start" BackgroundColor="White" Spacing="10">
<!--DocumentData-->
<Label Grid.Row="0" HorizontalOptions="CenterAndExpand" Text="Občanský průkaz" VerticalOptions="End" ></Label>
<StackLayout BackgroundColor="Green" VerticalOptions="FillAndExpand">
<ListView x:Name="list" BackgroundColor="Red"
HasUnevenRows="True"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
VerticalScrollBarVisibility="Never"
CachingStrategy="RecycleElement"
ItemsSource="{Binding Results, Mode=TwoWay}"
SeparatorVisibility="Default"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid BackgroundColor="Beige" Padding="10" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="15*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="12*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="1" Padding="0" Text ="{Binding FieldDescriptor}" HorizontalOptions="Start" BackgroundColor="Gray" HorizontalTextAlignment="Start"/>
<Label Grid.Column="3" Padding="0" Text="{Binding FieldValue}" FontSize="Small" TextColor="#6781a3" BackgroundColor="AliceBlue" HorizontalOptions="Start" HorizontalTextAlignment="Start">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding BindingContext.EditTextCommand, Source={x:Reference Name=list}}"
CommandParameter="{Binding .}"
/>
</Label.GestureRecognizers>
</Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</StackLayout>
Here is layout background code. I add three data to make a test.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
IEnumerable<DocumentData> data = new DocumentData[] { new DocumentData() { FieldDescriptor="test 1", FieldValue=1, FieldVisualData=1 } };
data = data.Append(new DocumentData() { FieldDescriptor = "test 2", FieldValue = 2, FieldVisualData = 2 });
data = data.Append(new DocumentData() { FieldDescriptor = "test 3", FieldValue = 3, FieldVisualData = 3 });
this.BindingContext = new ResultPageViewModel(data);
}
}
Here is ResultPageViewModels code.
using Acr.UserDialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
namespace XFormsListviewMvvm
{
public class ResultPageViewModel : BaseViewModel
{
public ObservableCollection<DocumentData> Results { get; } = new ObservableCollection<DocumentData>();
public ICommand EditTextCommand { get; }
object param = "";
public ResultPageViewModel(IEnumerable<DocumentData> data)
{
EditTextCommand = new Command<DocumentData>(async (key) => await EditTextAsync(key));
Load(data);
}
public void Load(IEnumerable<DocumentData> data)
{
foreach (var result in data)
{
var detail = new DocumentData()
{
FieldVisualData = result.FieldVisualData,
FieldDescriptor = result.FieldDescriptor,
FieldValue = result.FieldValue,
};
Results.Add(detail);
}
}
public async Task EditTextAsync(DocumentData param)
{
PromptResult pResult = await UserDialogs.Instance.PromptAsync(new PromptConfig
{
InputType = InputType.Password,
Text = param.FieldValue.ToString(),
Title = "Insert your Password",
});
if (pResult.Ok)
{
param.FieldValue = pResult.Text;
}
}
}
}
If you need to change the value, then layout will display it. you need to implement the BaseViewModel in the DocumentData.
namespace XFormsListviewMvvm
{
public class DocumentData:BaseViewModel
{
private object fieldVisualData = "Hello world";
public object FieldVisualData
{
get => fieldVisualData;
set => SetValue(ref fieldVisualData, value);
}
private object fieldValue = "Hello world";
public object FieldValue
{
get => fieldValue;
set => SetValue(ref fieldValue, value);
}
public object FieldDescriptor { get; internal set; }
}
}
=============Update===================
I add your controls:HorizontalScrollList code. And I change the from <Image Source="{Binding Results.FieldVisualData}"> to <Image Source="{Binding FieldVisualData}" >
Here is running gif.Image could be seen normally.
Here is editted layout.
<StackLayout Spacing="0">
<!--Pictures-->
<StackLayout VerticalOptions="Start" Spacing="0" >
<controls:HorizontalScrollList VerticalOptions="Start" HeightRequest="300" x:Name="carouselView" ItemsSource="{Binding Results, Mode=TwoWay}">
<controls:HorizontalScrollList.ItemTemplate>
<DataTemplate>
<Image Source="{Binding FieldVisualData}"
Margin="5">
<!--<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding HandlePreviewTapped, Source={x:Reference vm}}"
CommandParameter="{Binding}"/>
</Image.GestureRecognizers>-->
</Image>
</DataTemplate>
</controls:HorizontalScrollList.ItemTemplate>
</controls:HorizontalScrollList>
</StackLayout>
<StackLayout VerticalOptions="Start" BackgroundColor="White" Spacing="10">
<!--DocumentData-->
<Label Grid.Row="0" HorizontalOptions="CenterAndExpand" Text="Občanský průkaz" VerticalOptions="End" ></Label>
<StackLayout BackgroundColor="Green" VerticalOptions="FillAndExpand">
<ListView x:Name="list" BackgroundColor="Red"
HasUnevenRows="True"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
VerticalScrollBarVisibility="Never"
CachingStrategy="RecycleElement"
ItemsSource="{Binding Results, Mode=TwoWay}"
SeparatorVisibility="Default"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid BackgroundColor="Beige" Padding="10" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="15*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="12*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="1" Padding="0" Text ="{Binding FieldDescriptor}" HorizontalOptions="Start" BackgroundColor="Gray" HorizontalTextAlignment="Start"/>
<Label Grid.Column="3" Padding="0" Text="{Binding FieldValue}" FontSize="Small" TextColor="#6781a3" BackgroundColor="AliceBlue" HorizontalOptions="Start" HorizontalTextAlignment="Start">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding BindingContext.EditTextCommand, Source={x:Reference Name=list}}"
CommandParameter="{Binding .}"
/>
</Label.GestureRecognizers>
</Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</StackLayout>
Here is layout background code.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
IEnumerable<DocumentData> data = new DocumentData[] { new DocumentData() { FieldDescriptor="test 1", FieldValue=1, FieldVisualData= "https://aka.ms/campus.jpg" } };
data = data.Append(new DocumentData() { FieldDescriptor = "test 2", FieldValue = 2, FieldVisualData = "https://aka.ms/campus.jpg" });
data = data.Append(new DocumentData() { FieldDescriptor = "test 3", FieldValue = 3, FieldVisualData = "https://aka.ms/campus.jpg" });
this.BindingContext = new ResultPageViewModel(data);
}
}
I have a "Main" page in xaml which contains my cellview.
<ContentPage.Content>
<ListView
Margin="0,15,0,0"
SelectionMode="None"
RowHeight= "150"
ItemsSource="{Binding ObjectItems}">
<ListView.ItemTemplate>
<DataTemplate>
<viewcells:ObjectItemViewCell/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
In my CellView I want to add 2 convertors as BindableContext and to integrate them in some my fields:
<<?xml version="1.0" encoding="UTF-8"?>
<ViewCell 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"
xmlns:local="clr-namespace:OperaMobile.Views.Postlogin"
xmlns:converterFontFamily="clr-namespace:OperaMobile.Converters"
xmlns:converterColor="clr-namespace:OperaMobile.Converters"
mc:Ignorable="d"
x:Class="OperaMobile.ViewCells.ObjectItemViewCell">
<ViewCell.BindingContext>
<converterFontFamily:BoolToStringConverter x:Key="fontFamilyConverter"/>
<!--<converterColor:BoolToStringConverter x:Key="fontFamilyConverter"/>-->
</ViewCell.BindingContext>
<ViewCell.View>
<StackLayout>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80*"/>
<ColumnDefinition Width="50*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackLayout
Padding="0,10"
Grid.Column="0"
Grid.Row="0"
Margin="15,0"
VerticalOptions="Center"
Orientation="Horizontal">
<Image Source="pin"/>
<Label FontAttributes="Bold" Text="{Binding Label}" Grid.Column="0" Grid.Row="0"/>
</StackLayout>
<StackLayout
Grid.Column="0"
Grid.Row="1"
BindableLayout.ItemsSource="{Binding InfoBox.CountDetailsItemsRows}"
Orientation="Horizontal"
Margin="13,10,0,0">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label FontAttributes="Bold" Text="{Binding BoldLabelTitle}"/>
<Label Text="{Binding LabelValue}"/>
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
<ListView
Margin="15,0"
Grid.Column="0"
Grid.Row="1"
SeparatorVisibility="None"
HasUnevenRows="True"
IsEnabled="False"
VerticalScrollBarVisibility="Never"
ItemsSource="{Binding InfoBox.DetailsObjectInfos}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Grid.Column="1" Orientation="Horizontal" Padding="0" Spacing="0">
<Label FontAttributes="Bold" Text="{Binding BoldLabelTitle}" Padding="0"/>
<Label Text="{Binding LabelValue}"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackLayout VerticalOptions="Start" Grid.Column="1" Grid.RowSpan="2" Spacing="15" Padding="20,10" Orientation="Horizontal" HorizontalOptions="End">
<StackLayout.Resources>
<ResourceDictionary>
<converterColor:BoolToStringConverter
x:Key="colorConverter"
TrueValue="#0275BA"
FalseValue="#949494"/>
<converterFontFamily:BoolToStringConverter
x:Key="fontFamilyConverter"
TrueValue="FA-S"
FalseValue="FA-R"/>
</ResourceDictionary>
</StackLayout.Resources>
<!--"{Binding IsFavorite, Converter={StaticResource fontFamilyConverter}}-->
<Label FontSize="Medium" FontFamily="{Binding IsFavorite, Converter={StaticResource Key=fontFamilyConverter}}" TextColor="{Binding IsFavorite, Converter={StaticResource Key=fontFamilyConverter}}" Text="{StaticResource IconStar}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.ToggleFavoriteObjectCommand}" CommandParameter="{Binding Id}"/>
</Label.GestureRecognizers>
</Label>
<Label FontSize="Medium" Style="{DynamicResource BlueColorStyle}" Text="{StaticResource IconEye}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.ViewObjectDetailsCommand}" CommandParameter="{Binding Id}"/>
</Label.GestureRecognizers>
</Label>
<Label FontSize="Medium" Style="{DynamicResource BlueSolidColorStyle}" Text="{StaticResource IconPin}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.ViewObjectOnMapCommand}" CommandParameter="{Binding Id}"/>
</Label.GestureRecognizers>
</Label>
</StackLayout>
</Grid>
</StackLayout>
</ViewCell.View>
</ViewCell>
this is the VM of my main page where I added viewcell as DataTemplate, so here it is:
public class SearchObjectsViewModel : BaseViewModel, INotifyPropertyChanged
{
public SearchObjectsViewModel()
{
Task.Run(async () => { await GetObjectInstancesList(); });
ToggleFavoriteObjectCommand = new Command(async(data) => await ToggleFavoriteObjects(data));
ViewObjectDetailsCommand = new Command(async (data) => await GetObjectDetails(data));
ViewObjectOnMapCommand = new Command(async (data) => await ViewObjectOnMap(data));
}
#region Properties
private string searchedText;
public string SearchedText
{
get { return searchedText; }
set
{
SetProperty(ref searchedText, value);
ObjectsSearch(searchedText);
}
}
ObservableCollection<CustomPin> _objectItems { get; set; }
public ObservableCollection<CustomPin> ObjectItems
{
get
{
return _objectItems;
}
set
{
if (_objectItems != value)
{
_objectItems = value;
OnPropertyChanged(nameof(ObjectItems));
}
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
public ICommand ViewObjectOnMapCommand { get; set; }
public ICommand ViewObjectDetailsCommand { get; set; }
public ICommand ToggleFavoriteObjectCommand { get; set; }
#endregion
#region Methods
private async Task GetObjectInstancesList()
{
ObjectItems = new ObservableCollection<CustomPin>();
var objectsResponse = await ApiServiceProvider.GetObjectInstances();
Device.BeginInvokeOnMainThread(() =>
{
if (objectsResponse.Succeeded)
{
foreach (var item in objectsResponse.ObjectInstances)
{
CustomPin pinData = new CustomPin();
pinData.Id = item.IdObjectInstance;
pinData.Label = item.ObjectClassName;
pinData.IsFavorite = item.IsFavorite.HasValue ? item.IsFavorite.Value : false;
if (item.Points != null)
{
pinData.Position = new Position(item.Points.FirstOrDefault().Latitude, item.Points.FirstOrDefault().Longitude);
}
else
{
//add polygon
}
foreach (var s in item.Strings)
{
if (s.ShowInBallon)
{
pinData.InfoBox.DetailsObjectInfos.Add(new Models.MapModels.DetailsObjectInfo
{
BoldLabelTitle = s.ClassParameterName + ": ",
LabelValue = s.StringValue
});
}
}
foreach (var i in item.Integers)
{
if (i.ShowInBallon)
{
pinData.InfoBox.DetailsObjectInfos.Add(new Models.MapModels.DetailsObjectInfo
{
BoldLabelTitle = i.ClassParameterName + ": ",
LabelValue = i.IntValue.ToString()
});
}
}
foreach (var date in item.Dates)
{
if (date.ShowInBallon)
{
pinData.InfoBox.DetailsObjectInfos.Add(new Models.MapModels.DetailsObjectInfo
{
BoldLabelTitle = date.ClassParameterName + ": ",
LabelValue = date.DateValue.ToString()
});
}
}
ObjectItems.Add(pinData);
pinData.InfoBox.CountDetailsItemsRows = pinData.InfoBox.DetailsObjectInfos.Count * 85;
}
}
TemporalData.ObjectsData = ObjectItems;
OnPropertyChanged(nameof(ObjectItems));
OnPropertyChanged(nameof(TemporalData.ObjectsData));
});
}
private void ObjectsSearch(string searchedText)
{
if (!string.IsNullOrWhiteSpace(searchedText))
{
var result = TemporalData.ObjectsData.Where(x => x.Label.ToLowerInvariant().Contains(searchedText.ToLowerInvariant())).ToList();
ObjectItems = new ObservableCollection<CustomPin>(result);
}
else
{
ObjectItems = new ObservableCollection<CustomPin>(TemporalData.ObjectsData);
}
OnPropertyChanged(nameof(ObjectItems));
}
private async Task ViewObjectOnMap(object objectId)
{
CustomPin selectedPin = App.SelectedPin = ObjectItems.Where(x => x.Id == Convert.ToInt32(objectId)).FirstOrDefault();
App.GoToPinCommand = new Command(() => App.GoToPinCommand.Execute(selectedPin));
await Shell.Current.GoToAsync(Routes.MapPage);
}
private async Task GetObjectDetails(object objectId)
{
App.SelectedPin = ObjectItems.Where(x => x.Id == Convert.ToInt32(objectId)).FirstOrDefault();
await Shell.Current.GoToAsync(Routes.ItemDetailsPage);
}
private async Task ToggleFavoriteObjects(object objectId)
{
int id = Convert.ToInt32(objectId);
var objectItem = ObjectItems.Where(x => x.Id == id).FirstOrDefault();
var favoriteToggleResponse = await ApiServiceProvider.ToggleFavoriteObjectById(id, !objectItem.IsFavorite);
if (!favoriteToggleResponse.Succeeded)
{
await Shell.Current.DisplayAlert("Error", "Lost communication with server. Try again.", "OK");
}
else
{
ObjectItems.Where(x => x.Id == id).Select(c => { c.IsFavorite = !c.IsFavorite; return c; }).ToList();
}
}
#endregion
}
Im getting the error: BindingCOntext is set more than once.
Other issue that I have is that emulator does not recognize TapGestureRecognizer for example this Label which you can refer to up code:
<Label FontSize="Medium" FontFamily="{Binding IsFavorite, Converter={StaticResource Key=fontFamilyConverter}}" TextColor="{Binding IsFavorite, Converter={StaticResource Key=fontFamilyConverter}}" Text="{StaticResource IconStar}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.ToggleFavoriteObjectCommand}" CommandParameter="{Binding Id}"/>
</Label.GestureRecognizers>
</Label>
I need to put something like Command="{Binding Path=BindingContext.ToggleFavoriteObjectCommand,Source={x:Reference Page}}" but I don't know if I can reference "parrent page" in my case it would be a "Main" page where I invoke cellView.
Cause
You're setting BindingContext twice .
The first : actually the following code does set BindingContext automatically on Cell , the content is the item in list ObjectItems .
<ListView.ItemTemplate>
<DataTemplate>
<viewcells:ObjectItemViewCell/>
</DataTemplate>
</ListView.ItemTemplate>
The second
<ViewCell.BindingContext>
<converterFontFamily:BoolToStringConverter x:Key="fontFamilyConverter"/>
<!--<converterColor:BoolToStringConverter x:Key="fontFamilyConverter"/>-->
</ViewCell.BindingContext>
Solution
Do not set BindingContext inside ViewCell , if you want to use converter , you could add it in page directly .
<ListView
Margin="0,15,0,0"
SelectionMode="None"
RowHeight= "150"
ItemsSource="{Binding ObjectItems}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell BindingContext="{Binding Converter = {StaticResource fontFamilyConverter}}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The command does not trigger because the binding path is incorrect , place those commands into model CustomPin would solve the problem .
The problem is, you are setting converters in BindingContext tag. They needs to be set like this:
<ContentPage.BindingContext>
YOUR BINDING CONTEXT
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<converterFontFamily:BoolToStringConverter x:Key="fontFamilyConverter"/>
<converterColor:BoolToStringConverter x:Key="fontFamilyConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
Your commands not working because of BindingContext error.
I have a CaruselPage and inside the DataTemplate I have put a CollectionView
<CarouselPage.ItemTemplate>
<DataTemplate>
<ContentPage>
<ContentPage.Content>
<StackLayout>
<CollectionView
ItemsSource="{Binding Cards}"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center"
EmptyView="Non ci sono Card Formazione"
Margin="10"
x:Name="CV"
>
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="1" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Frame BorderColor="Black">
<StackLayout>
<Label Text="{Binding DisciplinaCard}" Style="{StaticResource LabelTesStyle}"/>
<Label Text="{Binding DataCard}" Style="{StaticResource LabelTesStyle}"/>
</StackLayout>
</Frame>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
</DataTemplate>
</CarouselPage.ItemTemplate>
I manage to populate the carusel page but I can't find how to populate the collection view.
All the solution that I find is for UWP, but I need to do this in xamarin.forms cross platform.
According to your description, you want to add collectionview control in CaruselPage, I do one sample that you can take a look.
Here is the CaruselPage:
<CarouselPage
x:Class="CaruselApp.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<CarouselPage.ItemTemplate>
<DataTemplate>
<ContentPage>
<StackLayout>
<Label Margin="10" Text="{Binding title}" />
<CollectionView ItemsSource="{Binding collections}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="1" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Frame BorderColor="Black">
<StackLayout>
<Label Text="{Binding Name}" />
<Label Text="{Binding Age}" />
</StackLayout>
</Frame>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage>
</DataTemplate>
</CarouselPage.ItemTemplate>
The Model in CollectionView:
public class CollectionModel
{
public string Name { get; set; }
public int Age { get; set; }
}
The Model in CarouselPage:
public class CaruselModel
{
public ObservableCollection<CollectionModel> collections { get; set; }
public string title { get; set; }
public static ObservableCollection<CaruselModel> carusels { get; set; }
static CaruselModel()
{
carusels = new ObservableCollection<CaruselModel>()
{
new CaruselModel(){title="title 1", collections=new ObservableCollection<CollectionModel>(){ new CollectionModel() { Name="Cherry",Age=12},new CollectionModel() { Name="barry",Age=23} } },
new CaruselModel(){title="title 2", collections=new ObservableCollection<CollectionModel>(){ new CollectionModel() { Name="Annine",Age=18},new CollectionModel() { Name="Wendy",Age=25} } },
new CaruselModel(){title="title 3", collections=new ObservableCollection<CollectionModel>(){ new CollectionModel() { Name="Mattew",Age=12},new CollectionModel() { Name="Leo",Age=23} } },
new CaruselModel(){title="title 4", collections=new ObservableCollection<CollectionModel>(){ new CollectionModel() { Name="Jessie",Age=12},new CollectionModel() { Name="Junior",Age=23} } },
new CaruselModel(){title="title 5", collections=new ObservableCollection<CollectionModel>(){ new CollectionModel() { Name="Jack",Age=12},new CollectionModel() { Name="Land",Age=23} } }
};
}
}
Please don't forget to add the following code in Android Mainactivity or ios AppDelegate, because you use CollectionView.
Forms.SetFlags("CollectionView_Experimental");
Here is the sample at Github, you can download to test.
https://github.com/CherryBu/CarouselApp
her is the screenshot:
I would like to get the value of a selectedItem in A listView,this is my code.
public class BlogClass{
public string NewId;
public BlogClass()
{
additem();
}
public class BlogViews
{
public string id { get; set; }
public string DisplayTopic { get; set; }
public string DisplayMain { get; set; }
public ImageSource BlogImageSource { get; set; }
}
public List<BlogViews> BlogList1 = new List<BlogViews>();
public void additem()
{
BlogList1.Add(new BlogViews { id = "1", DisplayMain = "Margret", DisplayTopic = "Mensah" });
BlogList1.Add(new BlogViews { id = "2", DisplayMain = "Maet", DisplayTopic = "Meah" });
BlogList1.Add(new BlogViews { id = "3", DisplayMain = "dargret", DisplayTopic = "sah" });
BlogList1.Add(new BlogViews { id = "4", DisplayMain = "gret", DisplayTopic = "Meh" });
BlogListView.ItemsSource = BlogList1;
}
}
<?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="demoListView.ImageCellPage">
<ContentPage.Content>
<ListView x:Name="BloglistView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="#eee"
Orientation="Vertical">
<StackLayout Orientation="Horizontal">
<Image Source="{Binding BlogImageSource}" />
<Label Text="{Binding id}"
TextColor="#f35e20" />
<Label Text="{Binding DisplayTopic}"
HorizontalOptions="EndAndExpand"
TextColor="#503026" />
<Label Text="{Binding DisplayMain}"
HorizontalOptions="EndAndExpand"
TextColor="#503026" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
Question
Now When i select an item on BlogListView I want to set the Value of NewId to that of id according to the selecteditem.Hence gatting the value of id
You just need to add ItemTapped event for the listview:
XAML:
<ListView x:Name="BloglistView" ItemTapped="Handle_ItemTapped">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="#eee"
Orientation="Vertical">
<StackLayout Orientation="Horizontal">
<Image Source="{Binding BlogImageSource}" />
<Label Text="{Binding id}"
TextColor="#f35e20" />
<Label Text="{Binding DisplayTopic}"
HorizontalOptions="EndAndExpand"
TextColor="#503026" />
<Label Text="{Binding DisplayMain}"
HorizontalOptions="EndAndExpand"
TextColor="#503026" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code Behind:
void Handle_ItemTapped(object sender, Xamarin.Forms.ItemTappedEventArgs e)
{
var selectedItem = e.Item as BlogViews;
NewId = selectedItem.id;
}