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.
CodePudding user response:
you are declaring ExpenseReport
public ObservableRangeCollection<ExpenseReport> ExpenseReport { get; set; }
but it will be null until you instantiate it
ExpenseReport = new ObservableRangeCollection<ExpenseReport>();
CodePudding user response:
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
.