I've bound it to an ObservableCollection
(PaidTrips
).
The goal is to create one (1) PDF for each distinct "CompanyName" in the LicenseHolderID
column.
To achieve this, I convert to a List
, and group by LicenseHolderID
.
var paidTrips = PaidTrips
.GroupBy(p => new {
p.LicenseHolderID
})
.ToList();
After that, I iterate over the list with a foreach
-loop:
foreach (var trip in paidTrips) {
// I grab the distinct name
string licenseholder = trip.Key.LicenseHolderID.ToString();
// I summarize many of the columns
decimal totalPayment = trip.Sum(x => x.Payment);
decimal totalPaymentNet = trip.Sum(x => x.Payment);
decimal totalOrderFee = trip.Sum(x => x.Payment);
decimal totalPaymentFee = trip.Sum(x => x.Payment);
// I grab the first value of some other columns, which won't change
string licenseholderInvoiceID = trip.Select(x => x.LicenseHolderInvoiceID).FirstOrDefault().ToString();
string ridelRegionInvoiceID = trip.Select(x => x.RidelRegionInvoiceID ).FirstOrDefault().ToString();
// Creating PDF document using PDFsharp:
// PDFsharp code
// PDFsharp code
// PDFsharp code
}
I am able to create a PDF-document, one for each distinct LicenseHolderID
, by adding the licenseHolderID
-string to the file-path of PDFsharps document.Save()
.
But I am not able to fill the PDF-document with all the information I need.
I have the summarized amounts - good, because I absolutely need to display the full invoice amount.
But -- I also need to go into detail. I do not have amounts per VehicleID
.
For "CompanyName1", that'd be AG4203000002 and AG4203000003, with their corresponding row data.
I did do this...
IEnumerable<string> vehicleIds = trip
.Select(x => x.VehicleID)
.Distinct()
.ToArray();
string vehicle = string.Join(", ", vehicleIds);
...in order to separate the VehicleID
distinct values from eachother.
I then put the string vehicle
into PDFsharps way of drawing text onto the PDF (DrawString
):
gfx.DrawString(vehicle, /* font and color customization */);
Which gives me the correct amount of VehicleID
for each LicenseHolderID
, but in one, long string... Not optimal.
Which brings me to my question: A): I need to bring along the row data of the other columns pertaining to the distinct vehicles in VehicleID
, so that I can fill in details in my PDFs, and not just the summarized values, and B): if the solution to A) involves getting rid of the long, hacky string (vehicle
), that'd be optimal, if not - that's okay too.
UPDATE (adding code from @Dai's answer):
// PaidTrip = My holder class, which I've bound to a ObservableCollection (PaidTrips)
var paidTrips = PaidTrips.ToList(); // I was unsure about this one
IEnumerable<IGrouping<String, PaidTrip>> tripsGroupedByCompany = paidTrips.GroupBy(pt => pt.LicenseHolderID);
foreach (IGrouping<String, PaidTrip>> companyGroup in tripsGroupedByCompany) {
string licenseHolderId = companyGroup.Key;
gfx.DrawString(/* code goes foo */);
// I tried adding Key here, but that gave me a squiggly under "t.VehicleID"
var groupedByVehicle = companyGroup.GroupBy(t => t.VehicleID);
foreach (IGrouping<String, PaidTrip> vehicleGroup in groupedByVehicle) {
// This is where I get a red squiggly; under Key
String vehicleId = groupedByVehicle.Key;
gfx.DrawString(/* code goes foo */);
foreach (PaidTrip trip in vehicleGroup) {
gfx.DrawString(/* code goes foo */);
}
}
}
This is the error:
CS1061: IEnumerable<IGrouping<string, PaidTrip>> does not contain a definition for 'Key' and no accessible extension method 'Key' accepting a first argument of type 'IEnumerable<IGrouping<string, PaidTrip>>' could be found (are you missing a using directive or an assembly reference?)
CodePudding user response:
I need to bring along the row data of the other columns pertaining to the distinct vehicles in
VehicleId
, so that I can fill in details in my PDFs, and not just the summarized values.
If I understand you correctly, for each company (LicenseHolderId
) you want their relevant Trip
objects, but grouped by VehicleId
- that's straightforward, just add another GroupBy
- and you can iterate over them in an inner foreach
:
List<Trip> paidTrips = ...
IEnumerable< IGrouping<String,Trip> > tripsGroupedByCompany = paidTrips.GroupBy( pt => pt.LicenseHolderId );
foreach( IGrouping<String,Trip> companyGroup in tripsGroupedByCompany )
{
String licenseHolderId = companyGroup.Key;
gfx.DrawString( "Company: " licenseHolderId "\r\n" );
var groupedByVehicle = companyGroup.GroupBy( t => t.VehicleId );
foreach( IGrouping<String,Trip> vehicleGroup in groupedByVehicle )
{
String vehicleId = vehicleGroup.Key;
gfx.DrawString( "\tVehicle: " vehicleId "\r\n" );
foreach( Trip trip in vehicleGroup )
{
gfx.DrawString( $"\t\tTrip: {trip.Year}-{trip.Month:00}. {trip.PaymentNet,11:C2}\r\n" );
}
}
}
I added some formatting instructions and characters which only really apply to text-mode (console applications), not PDF rendering, but if you're curious:
- I used tab characters (
\t
) to indicate indent so related data is visually grouped. - I used formatting specifier
:00
to ensure theMonth
value is displayed as a 2-digit value with a leading zero. - I used formatting specifier
,11:C2
to ensure thePaymentNet
value is formatted as a Currency value with 2 decimal places, and is always left-padded to at-least 11 characters width.
- I used tab characters (
This will give you output like this (below).
Note that while in your source-data each
VehicleId
has only a single trip associated with it, my code above allows a singleVehicleId
to have multiple trips with both the same, and different,LicenseHolderId
values, though the sample print-out below only shows 1 trip per Vehicle.
Company: CompanyName1
Vehicle: AG4203000002
Trip: 2021-07. $107,088.68
Vehicle: AG4203000003
Trip: 2021-07. $138,761.32
Company: CompanyName2:
Vehicle: AG4203000004
Trip: 2021-07. $129,264.15
Vehicle: AG4203000005
Trip: 2021-07. $87,273.58
But note that this code above is bad because it crosses concerns (it does 2 separate things: it traverses a non-trivial object-graph, and it renders data to your PDF library).
A better design would separate out the graph-traversal (perhaps to a single extension method) thus making the PDF rendering code much simpler, however I cannot give you any code examples of this without knowing more about your database design and if/how you're using EF.