Xamarin - Fill ListView with MySql Data - mysql

I'm kind of stuck and not getting anywhere. Here is my problem:
I want to populate a ListView with the data from a MySql database. Here is my class which contains the database queries:
DBConnection:
public ObservableRangeCollection<ExpenseReport> GetDataExpenseReport()
{
if (OpenConnection() == true)
{
DataExpense = new ObservableRangeCollection<ExpenseReport>();
MySqlCommand sc = new MySqlCommand();
sc.CommandText = "SELECT * FROM t_expensereport WHERE c_inputuser = #userid";
sc.Parameters.AddWithValue("#userid", User.Id);
sc.Connection = myConn;
MySqlDataReader dr = sc.ExecuteReader();
while (dr.Read())
{
DataExpense.Add(new ExpenseReport
{
Date = (DateTime)dr["c_date"],
Reason = (string)dr["c_reason"],
TripThereAndBack = (string)dr["c_tripThereAndBack"],
Vehicle = (string)dr["c_vehicle"],
Kilometers = (double)dr["c_kilometers"],
EuroProKm = (double)dr["c_euroProKm"],
TripCost = (double)dr["c_tripCost"],
Maut = (double)dr["c_maut"],
ParkingLot = (double)dr["c_parkingLot"],
Other = (double)dr["c_other"],
Accommodation = (double)dr["c_accommodation"],
Meal = (double)dr["c_meal"],
TrainTicket = (double)dr["c_trainTicket"]
});
}
dr.Close();
return DataExpense;
}
return null;
}
My Model ExpenseReport:
public class ExpenseReport
{
public DateTime Date { get; set; }
public string Reason { get; set; }
public string TripThereAndBack { get; set; }
public string Vehicle { get; set; }
public double Kilometers { get; set; }
public double EuroProKm { get; set; }
public double TripCost { get; set; }
public double Maut { get; set; }
public double ParkingLot { get; set; }
public double Other { get; set; }
public double Accommodation { get; set; }
public double Meal { get; set; }
public double TrainTicket { get; set; }
}
View:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewmodels="clr-namespace:Magazin.ViewModels.Dashboard"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
xmlns:model="clr-namespace:Magazin.Models"
x:Class="Magazin.Views.Dashboard.OverviewExpenseReportView"
Title="Übersicht Spesen">
<ContentPage.BindingContext>
<viewmodels:OverviewExpenseReportViewModel/>
</ContentPage.BindingContext>
<ContentPage.Behaviors>
<xct:EventToCommandBehavior
EventName="Appearing"
Command="{Binding RefreshCommand}" />
</ContentPage.Behaviors>
<ContentPage.Content>
<StackLayout>
<ListView
x:Name="OverviewER"
CachingStrategy="RecycleElement"
BackgroundColor="Transparent"
ItemsSource="{Binding ExpenseReport}"
HasUnevenRows="True"
SeparatorVisibility="None"
IsPullToRefreshEnabled="True"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
RefreshControlColor="Green"
RefreshCommand="{Binding RefreshCommand}">
<!---->
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:ExpenseReport">
<ViewCell>
<Grid Padding="10">
<Frame CornerRadius="20" HasShadow="True">
<StackLayout Orientation="Horizontal">
<StackLayout Padding="20,0,0,0">
<StackLayout>
<Label Text="{Binding Reason}" FontSize="Medium" VerticalOptions="Center" TextColor="Green" />
</StackLayout>
<StackLayout>
<Label Text="{Binding Kilometers, StringFormat='{}{0}km'}" FontSize="Small" VerticalOptions="Center"/>
<Label Text="{Binding Date, StringFormat='{0:dd.MM.yyyy}'}" FontSize="Small" VerticalOptions="Center"/>
<Label Text="{Binding TripCost}" FontSize="Small" VerticalOptions="Center"/>
</StackLayout>
</StackLayout>
</StackLayout>
</Frame>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Viewmodel OverviewExpenseReportViewModel
public class OverviewExpenseReportViewModel : ViewModelBase
{
public ObservableRangeCollection<ExpenseReport> ExpenseReportCollection { get; set; }
public AsyncCommand RefreshCommand { get; }
public OverviewExpenseReportViewModel()
{
RefreshCommand = new AsyncCommand(Refresh);
}
async Task Refresh()
{
ExpenseReportCollection = new ObservableRangeCollection<ExpenseReport>();
DBConnection db = new DBConnection();
await Task.Delay(1500);
ExpenseReportCollection.Clear();
ExpenseReportCollection.AddRange(db.GetDataExpenseReport());
}
}
I have long asked our friend Google but I somehow do not get anywhere. At this point
ExpenseReport.AddRange(db.GetDataExpenseReport()); I get the error that System.NullReferenceException: 'Object reference not set to an instance of an object.'
Can anyone help me on how I manage to populate the ListView, I appreciate any answers!
Lastly, I switched everything to ObservableRangeCollection from the MvvmHelpers dependency. But I always get this error, something I am doing wrong.

you are declaring ExpenseReport
public ObservableRangeCollection<ExpenseReport> ExpenseReport { get; set; }
but it will be null until you instantiate it
ExpenseReport = new ObservableRangeCollection<ExpenseReport>();

System.InvalidCastException: 'Specified cast is not valid.. Is
something wrong with that Line?
ExpenseReport.AddRange(db.GetDataExpenseReport());``
For this problem, you need to recheck the data type of the returned list and the object included in the returned list.
Suppose the returned type is IList<object>, then you cast IList<object> to List<ExpenseReport>,just as follows:
//initialize variable `ExpenseReport` here
ExpenseReportCollection = new ObservableRangeCollection<ExpenseReport>();
//suppose `data` is the returned data list
ExpenseReportCollection.AddRange(data as List<ExpenseReport>);
Suppose the type of returned Object(OtherObject) is not the same object(ExpenseReport), you need to iterate through the returned list one by one and then convert the returned Object to object ExpenseReport.

Related

Showing Marker on list of maps added in list view in Xamarin forms

I have added a map control under the grid view to show different locations, I want to show a pin or markedr on each of these maps. I am binding in the list the longitude and latitude against each location under the position object.
Below is the XAML:
<grial:GridView
Grid.Row="1"
ColumnSpacing="15"
RowSpacing="15"
ColumnCount="{
grial:OnOrientationInt
PortraitPhone=1,
LandscapePhone=2,
PortraitTablet=2,
LandscapeTablet=2,
PortraitDesktop=3,
LandscapeDesktop=3
}"
VerticalOptions="FillAndExpand"
ItemsSource="{ Binding Branches }">
<grial:GridView.ItemTemplate>
<DataTemplate>
<local:ArticleColumnItemTemplate>
</local:ArticleColumnItemTemplate>
</DataTemplate>
</grial:GridView.ItemTemplate>
</grial:GridView>
Below is the contentView:
<ContentView.Content>
<Grid
Padding="0">
<grial:CardView
BackgroundColor="White"
Padding="10"
CornerRadius="15"
RowSpacing="5"
Margin="{
grial:OnOrientationThickness
Default='5,5,5,5',
LandscapePhone='5,5,5,5'
}">
<grial:CardView.RowDefinitions>
<RowDefinition
Height="Auto" />
</grial:CardView.RowDefinitions>
<maps:Map x:Name="map"
HeightRequest="280"
MapType="Satellite"
Grid.Row="0">
<maps:Map.Pins>
<maps:Pin
Address="{Binding Branches.address.street1}"
Label="Label1"
Position="{Binding Branches.Position}"
Type="Place">
</maps:Pin>
</maps:Map.Pins>
</maps:Map>
</grial:CardView>
</Grid>
</ContentView.Content>
Below is my View model which I am binding on Page load
public class MapPageViewModel : INotifyPropertyChanged
{
private readonly string _variantPageName;
public event PropertyChangedEventHandler PropertyChanged;
public List<Branches> _branches;
public List<Branches> Branches
{
get => _branches;
set
{
_branches = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Branches"));
}
}
}
public MapPageViewModel()
{
LoadData();
}
public async void LoadData()
{
Branches = await GetApiCalls.ServiceClientInstance.GetBranches();
foreach(Branches item in Branches)
{
item.Position = new Position(Convert.ToDouble(item.address.location.latitude),
Convert.ToDouble(item.address.location.longitude));
}
}
}
Below are the branch and address classes:
public class Branches : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string branchName { get; set; }
public Address address { get; set; }
public Position _position;
public Position Position
{
get => _position;
set
{
_position = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Position"));
}
}
}
}
public class Address
{
public string street1 { get; set; }
public string street2 { get; set; }
public Location location { get; set; }
}
public class Location
{
public double? latitude { get; set; }
public double? longitude { get; set; }
}
I have also debug and got the position object being initiated with longitude and latitude but pins are not visible on each of these maps.
your binding expression is wrong
<maps:Pin Address="{Binding Branches.address.street1}"
Label="Label1"
Position="{Binding Branches.Position}"
Type="Place">
</maps:Pin>
it should be
<maps:Pin Address="{Binding address.street1}"
Label="Label1"
Position="{Binding Position}"
Type="Place">
</maps:Pin>

ListView in Xamarin using RestApi

I'm enable to solve this error. I wanted to display ListView of API data which is in large amount.
For example API contains this type of data :
[{"id":"666","employee_name":"xyz","employee_salary":"123","employee_age":"23","profile_image":""}]
Error screenshot:
Class.cs which i made after converting JSON to c#
public class employees
{
public string id { get; set; }
public string employee_name { get; set; }
public string employee_salary { get; set; }
public string employee_age { get; set; }
public string profile_image { get; set; }
}
This is the XAML.cs file where LoadData() is using for calling API
public async void LoadData()
{
var content = "";
HttpClient client = new HttpClient();
var RestURL = "MY API";
client.BaseAddress = new Uri(RestURL);
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(RestURL);
content = await response.Content.ReadAsStringAsync();
var Items = JsonConvert.DeserializeObject<List<employees>>(content);
ListView1.ItemsSource = Items;
}
This is the XAML file of Xamarin.Forms:
<StackLayout BackgroundColor="White">
<ListView x:Name="ListView1" RowHeight="60">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" Padding="8,0,8,0">
<Label Text="{Binding id}" TextColor="#000" FontSize="14" LineBreakMode="TailTruncation" />
<Label Text="{Binding employee_name}" TextColor="#000" LineBreakMode="TailTruncation" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
First need to create a local model class :
public class TodoItem
{
public string id { get; set; }
public string employee_name { get; set; }
public string employee_salary{ get; set; }
public bool employee_age { get; set; }
public bool profile_image { get; set; }
}
And in the RestService can use TodoItem:
public List<TodoItem> Items { get; private set; }
public async Task<List<TodoItem>> RefreshDataAsync ()
{
Items = new List<TodoItem> ();
// RestUrl = http://developer.xamarin.com:8081/api/todoitems
var uri = new Uri (string.Format (Constants.RestUrl, string.Empty));
try {
var response = await client.GetAsync (uri);
if (response.IsSuccessStatusCode) {
var content = await response.Content.ReadAsStringAsync ();
Items = JsonConvert.DeserializeObject <List<TodoItem>> (content);
}
} catch (Exception ex) {
Debug.WriteLine (#"ERROR {0}", ex.Message);
}
return Items;
}
And last where your listview itemsource can set as follow:
listView.ItemsSource = await RestService.RefreshDataAsync();
Note: Here is a official sample you can refer to.
I'm enable to solve this error, i wanted to display listview of API data which is in large amount
Showing large data in listview,here is a paging show method.After getting API data, saving them in local CacheListData.Not directly set it to listView.ItemsSource .And you need create a ItemListData to add data from CacheListData.Which the count of added data according to you once want to show.When listview scroll to bottom ,then show Add More Swipe method to reload next page data.
Generally, Solution is to cache lagre data to local first.Then get data a little by page to show.Here is a solution link can refer to.
You are using the wrong endpoint, you should use this one, to retrieve a list of employees
var RestURL = "http://dummy.restapiexample.com/api/v1/employees/";
You can check the API documentation

Parsing Multidimensional JSON Array and Attach to ListView in xamarin.froms

I am trying to parse the JSON that has multiple objects. I am trying to parse this json and set it to my custom ListView.
I have tried This
My JSON:
[
{"Product":"Product 1",
"Origins":
[
{"Origin":"XXX QQ",
"Details":
[
{"Seller":"Name","Seller_Rate":"256","Saller_QTY":"20","Buyer":"Name","Buyer_Rate":"256","Buyer_QTY":"20"},
{"Seller":"Name","Seller_Rate":"256","Saller_QTY":"20","Buyer":"Name","Buyer_Rate":"256","Buyer_QTY":"20"}
]
},
{"Origin":"ADAMI Oil",
"Details":
[
{"Seller":"Name","Seller_Rate":"256","Saller_QTY":"20","Buyer":"Name","Buyer_Rate":"256","Buyer_QTY":"20"},
{"Seller":"Name","Seller_Rate":"256","Saller_QTY":"20","Buyer":"Name","Buyer_Rate":"256","Buyer_QTY":"20"}
]
}
]
},
{"Product":"Product 2",
"Origins":
[
{"Origin":"YYY pp",
"Details":
[
{"Seller":"Name","Seller_Rate":"256","Saller_QTY":"20","Buyer":"Name","Buyer_Rate":"256","Buyer_QTY":"20"},
{"Seller":"Name","Seller_Rate":"256","Saller_QTY":"20","Buyer":"Name","Buyer_Rate":"256","Buyer_QTY":"20"}
]
},
{"Origin":"PQR CCC",
"Details":
[
{"Seller":"Name","Seller_Rate":"256","Saller_QTY":"20","Buyer":"Name","Buyer_Rate":"256","Buyer_QTY":"20"},
{"Seller":"Name","Seller_Rate":"256","Saller_QTY":"20","Buyer":"Name","Buyer_Rate":"256","Buyer_QTY":"20"}
]
}
]
}
]
My Object Class:
public class Products
{
public List<Origins> ListOrigin{ get; set; }
public string PRODUCT { get; set; }
public List<Products> product_list { get; set; }
public Products() {
product_list = new List<Products>();
}
}
public class Origins
{
public string Origin { get; set; }
public List<Details> ListDetails { get; set; }
}
public class Details
{
public string Seller { get; set; }
public string Seller_Rate { get; set; }
public string Saller_QTY { get; set; }
public string Buyer { get; set; }
public string Buyer_Rate { get; set; }
public string Buyer_QTY { get; set; }
}
And my call to the web service where i get JSON as i have shown.
public async Task<List<Products>> getProductsJson()
{
List<Products> res;
Log.Debug("Login", "in get products");
string responsejson = await client.GetStringAsync(Constants.url_getproducts);
Log.Debug("Login", responsejson);
res = JsonConvert.DeserializeObject<List<Products>>(responsejson);
/* foreach(Products p in res)
{
Log.Debug("Login1", p.PRODUCT);
foreach(Origins o in p.ListOrigin)
{
Log.Debug("Login1", o.Origin);
}
}*/
return res;
}
Here i have tried to print it in the log but it throws error and gets hanged.
this is how i have accessed the all data and list on the cs. page
List<Products> result = await App.RestService.getProductsJson();
//Log.Debug("Login",result[0].OriginsObj.Origin);
list_data.ItemsSource = result;
On the ListView I have tried to bind the data as:
<ListView x:Name="list_data" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<!--<TextCell Text="{Binding Topic}" TextColor="Purple" Detail="{Binding Description}" DetailColor="Black"/>-->
<!--<ImageCell Text="{Binding Topic}" TextColor="Purple" Detail="{Binding Description}" DetailColor="Black" ImageSource="{Binding ImageSource}" />-->
<ViewCell>
<ViewCell.View>
<StackLayout Spacing="5" >
<Label Text="{Binding PRODUCT}" FontSize="20" TextColor="Purple"/>
<Label Text="{Binding ListOrigin.Origin}" FontSize="20" TextColor="Purple"/>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
When i comment the for loop inside getProductsJson() method it works but. the Origin is not visible On The ListView, i know I am missing something but tired a lot not getting solution.

How to de-serialize json in c#?

I am trying to deserialize json, I'm getting an error:
"An exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.DLL but was not handled in user code"
My code:
public void w_StandingsDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (!string.IsNullOrEmpty(e.Result))
{
JsonSerializer jc = new JsonSerializer();
// var o = jc.Deserialize<RootObjectStandings>(e.Result);
var root3 = JsonConvert.DeserializeObject<RootObjectStandings>(e.Result);
// var root2 = JsonConvert.DeserializeObject<Headline>(e.Result);
football f = new football();
f.StandingList.ItemsSource = root3.info;
f.progressbar1.IsEnabled = false;
f.progressbar1.IsIndeterminate = false;
f.progressbar1.Visibility = Visibility.Collapsed;
}
}
Class:
public class RootObjectStandings
{
public int position { get; set; }
public int team_id { get; set; }
public string team { get; set; }
public string teamshort { get; set; }
public string teampath { get; set; }
public int played { get; set; }
public int won { get; set; }
public int drawn { get; set; }
public int lost { get; set; }
public int #for { get; set; }
public int against { get; set; }
public int difference { get; set; }
public Home home { get; set; }
public Away away { get; set; }
public int points { get; set; }
public string info { get; set; }
}
and xaml code:
<ListBox x:Name="StandingList" FontFamily="Arial Black" VerticalAlignment="Center" Margin="-6,0,0,-26" Height="610" RenderTransformOrigin="0.5,0.5" Background="{x:Null}" Opacity="0.8">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Button Style="{StaticResource ButtonStyle1}" Width="450" Height="Auto" Background="Black" BorderBrush="Transparent" FontWeight="Bold" FontSize="23" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,0,0,5" Opacity="0.95" Foreground="White">
<StackPanel>
<TextBlock TextWrapping="Wrap" FontFamily="Segoe WP Black" Foreground="White" FontSize="18" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" TextAlignment="Left" Width="350" Height="150">
<Run FontSize="23" Text="{Binding info}" />
<LineBreak/>
<Run Text="{Binding position}" FontWeight="Normal" FontSize="16" FontFamily="Segoe WP SemiLight"/>
</TextBlock>
</StackPanel>
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
What is going wrong? help

Bind ImageSource in Windows Phone

I am Using LazyListBox as given below.There is an Image in Data Template.And I am not able to Bind the ImageUrl.How can i Bind ImageSource.
<lazy:LazyListBox x:Name="d" ItemSource={Binding ProductImageLIst}>
<lazy:LazyListBox.LoadedItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Product_Id}" Foreground="Black"></TextBlock>
<Image x:Name="img" Source="{Binding Path=ImageUrl}"></Image>
</StackPanel>
</DataTemplate>
</lazy:LazyListBox.LoadedItemTemplate>
</lazy:LazyListBox>
And my ProductImageList Class is Shown Below
public class ProductImageList
{
public string ImageId { get; set; }
public string ImageUrl{ get; set; }
public string Product_Id { get; set; }
public string Category_id { get; set; }
public ProductImageList()
{
}
public ProductImageList(string imageid, string imageurl, string productid,string catid)
{
this.ImageId = imageid;
this.ImageUrl = imageurl;
this.Product_Id = productid;
this.Category_id = catid;
}
}
Use BitmapImage to bind source of image in LazyListBox control. Here is the solution. If your 'ImageUrl' is a http url you should first download image from this url and create BitmapImage by downloaded image stream, and if your imageUrl is a relative url create BitmapImage as below.
<lazy:LazyListBox x:Name="d" ItemSource={Binding ProductImageLIst}>
<lazy:LazyListBox.LoadedItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Product_Id}" Foreground="Black"></TextBlock>
<Image x:Name="img" Source="{Binding Path=ImageSource}"></Image>
</StackPanel>
</DataTemplate>
</lazy:LazyListBox.LoadedItemTemplate>
</lazy:LazyListBox>
public class ProductImageList
{
public string ImageId { get; set; }
public string ImageUrl{ get; set; }
public string Product_Id { get; set; }
public string Category_id { get; set; }
public BitmapImage ImageSource{get;set;}
public ProductImageList()
{
}
public ProductImageList(string imageid, string imageurl, string productid,string catid)
{
this.ImageId = imageid;
this.ImageUrl = imageurl;
this.Product_Id = productid;
this.Category_id = catid;
this.ImageSource = new BitmapImage(new Uri(imageurl, UriKind.RelativeOrAbsolute));
}
}