Fixed printing problems on Windows 8. Since printing is broken on Windows 8, the XPS viewer will be opened directly.
Fixed wrong dates in printed document if tenant entered or departed.
This commit is contained in:
@@ -3,18 +3,24 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||||||
# Visual Studio Version 16
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 16.0.30128.74
|
VisualStudioVersion = 16.0.30128.74
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ucalc", "ucalc\ucalc.csproj", "{E565705A-BAF4-4653-99A1-199C314A21EC}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ucalc", "ucalc\ucalc.csproj", "{E565705A-BAF4-4653-99A1-199C314A21EC}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{E565705A-BAF4-4653-99A1-199C314A21EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{E565705A-BAF4-4653-99A1-199C314A21EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{E565705A-BAF4-4653-99A1-199C314A21EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{E565705A-BAF4-4653-99A1-199C314A21EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E565705A-BAF4-4653-99A1-199C314A21EC}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{E565705A-BAF4-4653-99A1-199C314A21EC}.Debug|x64.Build.0 = Debug|x64
|
||||||
{E565705A-BAF4-4653-99A1-199C314A21EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{E565705A-BAF4-4653-99A1-199C314A21EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{E565705A-BAF4-4653-99A1-199C314A21EC}.Release|Any CPU.Build.0 = Release|Any CPU
|
{E565705A-BAF4-4653-99A1-199C314A21EC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E565705A-BAF4-4653-99A1-199C314A21EC}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{E565705A-BAF4-4653-99A1-199C314A21EC}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
+3
-3
@@ -47,9 +47,9 @@ namespace UCalc
|
|||||||
var dinA4MarginLeftRight = (double) converter.ConvertFromInvariantString("3.18cm");
|
var dinA4MarginLeftRight = (double) converter.ConvertFromInvariantString("3.18cm");
|
||||||
var dinA4MarginTopBottom = (double) converter.ConvertFromInvariantString("2.54cm");
|
var dinA4MarginTopBottom = (double) converter.ConvertFromInvariantString("2.54cm");
|
||||||
|
|
||||||
PrintDefaultFontSize = (double) converter.ConvertFromInvariantString("14pt");
|
PrintDefaultFontSize = (double) converter.ConvertFromInvariantString("11pt");
|
||||||
PrintSubjectFontSize = (double) converter.ConvertFromInvariantString("16pt");
|
PrintSubjectFontSize = (double) converter.ConvertFromInvariantString("12pt");
|
||||||
PrintNewlineFontSize = (double) converter.ConvertFromInvariantString("14pt");
|
PrintNewlineFontSize = (double) converter.ConvertFromInvariantString("11pt");
|
||||||
// ReSharper restore PossibleNullReferenceException
|
// ReSharper restore PossibleNullReferenceException
|
||||||
|
|
||||||
DinA4Padding = new Thickness(dinA4MarginLeftRight, dinA4MarginTopBottom, dinA4MarginLeftRight,
|
DinA4Padding = new Thickness(dinA4MarginLeftRight, dinA4MarginTopBottom, dinA4MarginLeftRight,
|
||||||
|
|||||||
@@ -1,109 +1,443 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Packaging;
|
using System.IO.Packaging;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Printing;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Documents;
|
using System.Windows.Documents;
|
||||||
using System.Windows.Markup;
|
using System.Windows.Media;
|
||||||
using System.Windows.Xps.Packaging;
|
using System.Windows.Xps.Packaging;
|
||||||
using System.Windows.Xps.Serialization;
|
using System.Windows.Xps.Serialization;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using UCalc.Data;
|
||||||
|
|
||||||
namespace UCalc.Controls
|
namespace UCalc.Controls
|
||||||
{
|
{
|
||||||
|
public class NoPrinterException : Exception
|
||||||
|
{
|
||||||
|
public NoPrinterException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class PrintableDocument : IDisposable
|
public class PrintableDocument : IDisposable
|
||||||
{
|
{
|
||||||
private static readonly Uri DocUri = new Uri($"pack://mietrechner{new Guid()}.xps");
|
private static readonly Uri DocUri = new Uri($"pack://mietrechner{new Guid()}.xps");
|
||||||
private readonly Package _package;
|
private readonly Package _package;
|
||||||
private readonly XpsDocument _document;
|
private readonly FlowDocument _flowDocument;
|
||||||
|
private readonly FixedDocumentSequence _previewDocument;
|
||||||
|
private XpsDocument _fixedDocument;
|
||||||
|
|
||||||
private int PageCount =>
|
public PrintableDocument(Billing billing, IEnumerable<Tenant> tenants)
|
||||||
_document.GetFixedDocumentSequence()!.References.First().GetDocument(false)!.Pages.Count;
|
|
||||||
|
|
||||||
public PrintableDocument(IDocumentPaginatorSource source)
|
|
||||||
{
|
{
|
||||||
_package = Package.Open(new MemoryStream(), FileMode.Create, FileAccess.ReadWrite);
|
_package = Package.Open(new MemoryStream(), FileMode.Create, FileAccess.ReadWrite);
|
||||||
|
|
||||||
PackageStore.AddPackage(DocUri, _package);
|
PackageStore.AddPackage(DocUri, _package);
|
||||||
|
|
||||||
_document = new XpsDocument(_package, CompressionOption.SuperFast, DocUri.AbsoluteUri);
|
_flowDocument = CreateFlowDocument(billing, tenants);
|
||||||
var manager = new XpsSerializationManager(new XpsPackagingPolicy(_document), false);
|
_previewDocument = CreatePreview(_flowDocument);
|
||||||
|
|
||||||
var paginator = source.DocumentPaginator;
|
|
||||||
manager.SaveAsXaml(paginator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
((IDisposable) _document).Dispose();
|
((IDisposable) _fixedDocument).Dispose();
|
||||||
((IDisposable) _package).Dispose();
|
|
||||||
PackageStore.RemovePackage(DocUri);
|
PackageStore.RemovePackage(DocUri);
|
||||||
|
((IDisposable) _package).Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Size? GetPrinterMediaSize()
|
||||||
|
{
|
||||||
|
var localPrintServer = new LocalPrintServer();
|
||||||
|
|
||||||
|
var size = localPrintServer.GetPrintQueues()
|
||||||
|
.Select(printQueue => printQueue.DefaultPrintTicket?.PageMediaSize)
|
||||||
|
.FirstOrDefault(mediaSize => mediaSize is {PageMediaSizeName: PageMediaSizeName.ISOA4});
|
||||||
|
if (size == null || !size.Width.HasValue || !size.Height.HasValue)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Size(size.Width!.Value, size.Height!.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PreviewIn(DocumentViewer viewer)
|
public void PreviewIn(DocumentViewer viewer)
|
||||||
{
|
{
|
||||||
viewer.Document = _document.GetFixedDocumentSequence();
|
viewer.Document = _previewDocument;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Print(string description)
|
public void Print(string description)
|
||||||
{
|
{
|
||||||
var dialog = new PrintDialog {UserPageRangeEnabled = true, MinPage = 1, MaxPage = (uint) PageCount};
|
var version = (int) Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
|
||||||
|
"CurrentMajorVersionNumber", 8);
|
||||||
|
|
||||||
if (dialog.ShowDialog() == true)
|
if (version == 10)
|
||||||
{
|
{
|
||||||
var documentSequence = _document.GetFixedDocumentSequence();
|
PrintDocumentImageableArea imageableArea = null;
|
||||||
Package convPackage = null;
|
var pageRangeSelection = PageRangeSelection.AllPages;
|
||||||
XpsDocument convDocument = null;
|
PageRange pageRange;
|
||||||
|
|
||||||
try
|
var writer = PrintQueue.CreateXpsDocumentWriter(description, ref imageableArea, ref pageRangeSelection,
|
||||||
|
ref pageRange);
|
||||||
|
if (writer == null)
|
||||||
{
|
{
|
||||||
if (dialog.PageRangeSelection == PageRangeSelection.UserPages)
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var clonedDocument = CloneFlowDocument(_flowDocument);
|
||||||
|
clonedDocument.PagePadding = Constants.DinA4Padding;
|
||||||
|
clonedDocument.ColumnWidth = double.PositiveInfinity;
|
||||||
|
|
||||||
|
var paginator = ((IDocumentPaginatorSource) clonedDocument).DocumentPaginator;
|
||||||
|
paginator.PageSize = new Size(imageableArea.MediaSizeWidth, imageableArea.MediaSizeHeight);
|
||||||
|
|
||||||
|
paginator.ComputePageCount();
|
||||||
|
|
||||||
|
if (pageRangeSelection == PageRangeSelection.UserPages)
|
||||||
|
{
|
||||||
|
if (pageRange.PageFrom > paginator.PageCount || pageRange.PageTo > paginator.PageCount ||
|
||||||
|
pageRange.PageFrom > pageRange.PageTo)
|
||||||
{
|
{
|
||||||
convDocument = ExtractPages(_document, dialog.PageRange.PageFrom - 1,
|
MessageBox.Show("Die eingegebenen Seitenzahlen sind ungültig!", "Ungültig!",
|
||||||
dialog.PageRange.PageTo - 1, out convPackage);
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
documentSequence = convDocument.GetFixedDocumentSequence();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.PrintDocument(documentSequence!.DocumentPaginator, description);
|
paginator = new LimitedPaginator(paginator, pageRange.PageFrom - 1, pageRange.PageTo - 1);
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
|
writer.Write(paginator);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var appDataPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}/UCalc";
|
||||||
|
var path = $"{appDataPath}\\print.xps";
|
||||||
|
|
||||||
|
if (File.Exists(path))
|
||||||
{
|
{
|
||||||
convDocument?.Close();
|
File.Delete(path);
|
||||||
convPackage?.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var xpsDocument = new XpsDocument(path, FileAccess.ReadWrite);
|
||||||
|
using var manager = new XpsSerializationManager(new XpsPackagingPolicy(xpsDocument), false);
|
||||||
|
|
||||||
|
var paginator = ((IDocumentPaginatorSource) _flowDocument).DocumentPaginator;
|
||||||
|
manager.SaveAsXaml(paginator);
|
||||||
|
|
||||||
|
xpsDocument.Close();
|
||||||
|
|
||||||
|
var process = new Process();
|
||||||
|
process.StartInfo = new ProcessStartInfo(path)
|
||||||
|
{
|
||||||
|
UseShellExecute = true
|
||||||
|
};
|
||||||
|
process.Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static XpsDocument ExtractPages(XpsDocument source, int fromPage, int toPage, out Package package)
|
private FixedDocumentSequence CreatePreview(IDocumentPaginatorSource document)
|
||||||
{
|
{
|
||||||
package = Package.Open(new MemoryStream(), FileMode.Create, FileAccess.ReadWrite);
|
_fixedDocument = new XpsDocument(_package, CompressionOption.SuperFast, DocUri.AbsoluteUri);
|
||||||
|
using var manager = new XpsSerializationManager(new XpsPackagingPolicy(_fixedDocument), false);
|
||||||
|
|
||||||
var docUri = new Uri("pack://mietrechnerTempTicket.xps");
|
var paginator = document.DocumentPaginator;
|
||||||
PackageStore.RemovePackage(docUri);
|
manager.SaveAsXaml(paginator);
|
||||||
PackageStore.AddPackage(docUri, package);
|
return _fixedDocument.GetFixedDocumentSequence();
|
||||||
|
}
|
||||||
|
|
||||||
var document = new XpsDocument(package, CompressionOption.SuperFast, docUri.AbsoluteUri);
|
private static FlowDocument CloneFlowDocument(FlowDocument document)
|
||||||
var pages = source.GetFixedDocumentSequence()!.References.First().GetDocument(false)!.Pages;
|
{
|
||||||
|
var sourceRange = new TextRange(document.ContentStart, document.ContentEnd);
|
||||||
|
|
||||||
var documentReference = new DocumentReference();
|
using var stream = new MemoryStream();
|
||||||
var fixedDocument = new FixedDocument();
|
sourceRange.Save(stream, DataFormats.Xaml);
|
||||||
documentReference.SetDocument(fixedDocument);
|
|
||||||
|
|
||||||
for (var i = fromPage; i <= toPage; ++i)
|
var targetDocument = new FlowDocument();
|
||||||
|
var targetRange = new TextRange(targetDocument.ContentStart, targetDocument.ContentEnd);
|
||||||
|
targetRange.Load(stream, DataFormats.Xaml);
|
||||||
|
|
||||||
|
return targetDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LimitedPaginator : DocumentPaginator
|
||||||
|
{
|
||||||
|
private readonly DocumentPaginator _paginator;
|
||||||
|
private readonly int _minPage;
|
||||||
|
private readonly int _maxPage;
|
||||||
|
|
||||||
|
public LimitedPaginator(DocumentPaginator paginator, int minPage, int maxPage)
|
||||||
{
|
{
|
||||||
var page = pages[i];
|
_paginator = paginator;
|
||||||
var pageContentChild = new PageContent {Source = page.Source};
|
_minPage = minPage;
|
||||||
((IUriContext) pageContentChild).BaseUri = ((IUriContext) page).BaseUri;
|
_maxPage = maxPage;
|
||||||
pageContentChild.GetPageRoot(false);
|
|
||||||
fixedDocument.Pages.Add(pageContentChild);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var documentSequence = new FixedDocumentSequence();
|
public override DocumentPage GetPage(int pageNumber)
|
||||||
documentSequence.References.Add(documentReference);
|
{
|
||||||
|
return _paginator.GetPage(_minPage + pageNumber);
|
||||||
|
}
|
||||||
|
|
||||||
var writer = XpsDocument.CreateXpsDocumentWriter(document);
|
public override bool IsPageCountValid => _minPage < _paginator.PageCount &&
|
||||||
writer.Write(documentSequence);
|
_maxPage < _paginator.PageCount &&
|
||||||
|
_minPage <= _maxPage;
|
||||||
|
|
||||||
|
public override int PageCount => _maxPage - _minPage + 1;
|
||||||
|
|
||||||
|
public override Size PageSize
|
||||||
|
{
|
||||||
|
get => _paginator.PageSize;
|
||||||
|
set => _paginator.PageSize = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IDocumentPaginatorSource Source => _paginator.Source;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FlowDocument CreateFlowDocument(Billing billing, IEnumerable<Tenant> tenants)
|
||||||
|
{
|
||||||
|
var size = GetPrinterMediaSize();
|
||||||
|
if (!size.HasValue)
|
||||||
|
{
|
||||||
|
throw new NoPrinterException("Failed to query printer");
|
||||||
|
}
|
||||||
|
|
||||||
|
var document = new FlowDocument
|
||||||
|
{
|
||||||
|
PageWidth = size.Value.Width,
|
||||||
|
PageHeight = size.Value.Height,
|
||||||
|
PagePadding = Constants.DinA4Padding,
|
||||||
|
ColumnWidth = double.PositiveInfinity
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var tenant in tenants)
|
||||||
|
{
|
||||||
|
var result = BillingCalculator.CalculateForTenant(billing, tenant);
|
||||||
|
AddPagesForTenant(document, billing, tenant, result);
|
||||||
|
}
|
||||||
|
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void AddLineBreaks(TableRowGroup rowGroup, int count)
|
||||||
|
{
|
||||||
|
var row = new TableRow();
|
||||||
|
rowGroup.Rows.Add(row);
|
||||||
|
|
||||||
|
var cell = new TableCell {ColumnSpan = 2};
|
||||||
|
row.Cells.Add(cell);
|
||||||
|
cell.Blocks.Add(new Paragraph(new Run(new string('\n', count - 1))
|
||||||
|
{FontSize = Constants.PrintNewlineFontSize}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddText(TableRowGroup rowGroup, string text, double? fontSize = null,
|
||||||
|
bool alignRight = false)
|
||||||
|
{
|
||||||
|
var row = new TableRow();
|
||||||
|
rowGroup.Rows.Add(row);
|
||||||
|
|
||||||
|
var cell = new TableCell {ColumnSpan = 2};
|
||||||
|
row.Cells.Add(cell);
|
||||||
|
|
||||||
|
if (alignRight)
|
||||||
|
{
|
||||||
|
cell.TextAlignment = TextAlignment.Right;
|
||||||
|
}
|
||||||
|
|
||||||
|
var paragraph = new Paragraph(new Run(text));
|
||||||
|
cell.Blocks.Add(paragraph);
|
||||||
|
|
||||||
|
if (fontSize != null)
|
||||||
|
{
|
||||||
|
paragraph.FontSize = fontSize.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddPagesForTenant(FlowDocument document, Billing billing, Tenant tenant,
|
||||||
|
TenantCalculationResult result)
|
||||||
|
{
|
||||||
|
var section = new Section {BreakPageBefore = true, FontSize = Constants.PrintDefaultFontSize};
|
||||||
|
document.Blocks.Add(section);
|
||||||
|
|
||||||
|
var table = new Table {CellSpacing = 0};
|
||||||
|
section.Blocks.Add(table);
|
||||||
|
table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)});
|
||||||
|
table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)});
|
||||||
|
|
||||||
|
var rowGroup = new TableRowGroup();
|
||||||
|
table.RowGroups.Add(rowGroup);
|
||||||
|
|
||||||
|
void AddCost(string name, decimal amount, bool isLast = false)
|
||||||
|
{
|
||||||
|
var row2 = new TableRow();
|
||||||
|
rowGroup.Rows.Add(row2);
|
||||||
|
|
||||||
|
if (isLast)
|
||||||
|
{
|
||||||
|
row2.Background = Brushes.LightGray;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cell2 = new TableCell
|
||||||
|
{BorderBrush = Brushes.Gray, BorderThickness = new Thickness(1, 1, 0, isLast ? 1 : 0)};
|
||||||
|
row2.Cells.Add(cell2);
|
||||||
|
|
||||||
|
cell2.Blocks.Add(new Paragraph(new Run(name)) {Padding = new Thickness(6)});
|
||||||
|
|
||||||
|
cell2 = new TableCell
|
||||||
|
{
|
||||||
|
BorderBrush = Brushes.Gray, BorderThickness = new Thickness(1, 1, 1, isLast ? 1 : 0),
|
||||||
|
TextAlignment = TextAlignment.Right
|
||||||
|
};
|
||||||
|
row2.Cells.Add(cell2);
|
||||||
|
|
||||||
|
cell2.Blocks.Add(new Paragraph(new Run($"{amount.CeilToString()} €")) {Padding = new Thickness(6)});
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddTextLeftRight(string leftText, string rightText)
|
||||||
|
{
|
||||||
|
var row2 = new TableRow();
|
||||||
|
rowGroup.Rows.Add(row2);
|
||||||
|
|
||||||
|
var cell2 = new TableCell();
|
||||||
|
row2.Cells.Add(cell2);
|
||||||
|
|
||||||
|
cell2.Blocks.Add(new Paragraph(new Run(leftText)));
|
||||||
|
|
||||||
|
cell2 = new TableCell
|
||||||
|
{
|
||||||
|
TextAlignment = TextAlignment.Right
|
||||||
|
};
|
||||||
|
row2.Cells.Add(cell2);
|
||||||
|
|
||||||
|
cell2.Blocks.Add(new Paragraph(new Run(rightText)));
|
||||||
|
}
|
||||||
|
|
||||||
|
AddTextLeftRight(
|
||||||
|
$"{billing.Landlord.Name}\n" +
|
||||||
|
$"{billing.Landlord.Address.Street} {billing.Landlord.Address.HouseNumber}\n" +
|
||||||
|
$"{billing.Landlord.Address.Postcode} {billing.Landlord.Address.City}\n" +
|
||||||
|
$"Telefon: {billing.Landlord.Phone}" +
|
||||||
|
(string.IsNullOrEmpty(billing.Landlord.MailAddress) ? "" : $"\nEmail: {billing.Landlord.MailAddress}"),
|
||||||
|
DateTime.Now.ToString(Constants.DateFormat)
|
||||||
|
);
|
||||||
|
|
||||||
|
AddLineBreaks(rowGroup, 2);
|
||||||
|
|
||||||
|
AddText(
|
||||||
|
rowGroup,
|
||||||
|
$"{tenant.Salutation.AsString()} {tenant.Name}\n" +
|
||||||
|
$"{billing.House.Address.Street} {billing.House.Address.HouseNumber}\n" +
|
||||||
|
$"{billing.House.Address.Postcode} {billing.House.Address.City}"
|
||||||
|
);
|
||||||
|
|
||||||
|
AddLineBreaks(rowGroup, 4);
|
||||||
|
|
||||||
|
AddText(rowGroup, $"{tenant.Salutation.AsString()} {tenant.Name}");
|
||||||
|
|
||||||
|
AddLineBreaks(rowGroup, 1);
|
||||||
|
|
||||||
|
var startDate = billing.StartDate;
|
||||||
|
if (tenant.EntryDate.HasValue && tenant.EntryDate.Value > startDate)
|
||||||
|
{
|
||||||
|
startDate = tenant.EntryDate.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var endDate = billing.EndDate;
|
||||||
|
if (tenant.DepartureDate.HasValue && tenant.DepartureDate.Value < endDate)
|
||||||
|
{
|
||||||
|
endDate = tenant.DepartureDate.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddText(
|
||||||
|
rowGroup,
|
||||||
|
$"Nebenkostenabrechnung vom {startDate.ToString(Constants.DateFormat)} zum {endDate.ToString(Constants.DateFormat)}",
|
||||||
|
Constants.PrintSubjectFontSize
|
||||||
|
);
|
||||||
|
|
||||||
|
AddLineBreaks(rowGroup, 1);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(tenant.CustomMessage1))
|
||||||
|
{
|
||||||
|
AddText(rowGroup, tenant.CustomMessage1);
|
||||||
|
|
||||||
|
AddLineBreaks(rowGroup, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (cost, costResult) in result.Costs)
|
||||||
|
{
|
||||||
|
AddCost(cost.Name, costResult.TotalAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddCost("Zwischensumme", result.SubTotalAmount);
|
||||||
|
AddCost("Bereits gezahlt", tenant.PaidRent);
|
||||||
|
AddCost(result.TotalAmount > 0 ? "Einmalige Nachzahlung" : "Einmalige Rückzahlung", result.TotalAmount,
|
||||||
|
true);
|
||||||
|
|
||||||
|
AddLineBreaks(rowGroup, 1);
|
||||||
|
|
||||||
|
if (result.TotalAmount > 0)
|
||||||
|
{
|
||||||
|
AddText(
|
||||||
|
rowGroup,
|
||||||
|
$"Bitte überweisen Sie den einmaligen Betrag von {result.TotalAmount.CeilToString()} € auf das untenstehende Konto."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddText(
|
||||||
|
rowGroup,
|
||||||
|
$"Der einmalige Betrag von {(result.TotalAmount * -1).CeilToString()} € wird in den nächsten Tagen auf Ihr Konto überwiesen."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddLineBreaks(rowGroup, 1);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(tenant.CustomMessage2))
|
||||||
|
{
|
||||||
|
AddText(rowGroup, tenant.CustomMessage2);
|
||||||
|
AddLineBreaks(rowGroup, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddText(rowGroup, "Kontoverbindung:");
|
||||||
|
AddText(rowGroup, $"IBAN: {billing.Landlord.BankAccount.Iban}");
|
||||||
|
AddText(rowGroup, $"BIC: {billing.Landlord.BankAccount.Bic}");
|
||||||
|
AddText(rowGroup, $"Name der Bank: {billing.Landlord.BankAccount.BankName}");
|
||||||
|
|
||||||
|
AddLineBreaks(rowGroup, 2);
|
||||||
|
|
||||||
|
AddText(rowGroup, "Mit freundlichen Grüßen");
|
||||||
|
|
||||||
|
if (result.Costs.Any(t => t.Key.DisplayInBill))
|
||||||
|
{
|
||||||
|
AddPagesForTenantDetails(document, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddPagesForTenantDetails(FlowDocument document, TenantCalculationResult result)
|
||||||
|
{
|
||||||
|
var section = new Section {BreakPageBefore = true, FontSize = Constants.PrintDefaultFontSize};
|
||||||
|
document.Blocks.Add(section);
|
||||||
|
|
||||||
|
var table = new Table {CellSpacing = 0};
|
||||||
|
section.Blocks.Add(table);
|
||||||
|
table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)});
|
||||||
|
table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)});
|
||||||
|
|
||||||
|
var rowGroup = new TableRowGroup();
|
||||||
|
table.RowGroups.Add(rowGroup);
|
||||||
|
|
||||||
|
AddText(rowGroup, "Details zur Berechnung:");
|
||||||
|
|
||||||
|
AddLineBreaks(rowGroup, 1);
|
||||||
|
|
||||||
|
foreach (var (cost, costResult) in result.Costs)
|
||||||
|
{
|
||||||
|
if (!cost.DisplayInBill)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddText(rowGroup, costResult.Details);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,15 +17,6 @@
|
|||||||
Icon="logo.ico">
|
Icon="logo.ico">
|
||||||
|
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<FlowDocumentScrollViewer x:Name="ScrollViewer"
|
|
||||||
Visibility="Collapsed">
|
|
||||||
<FlowDocument x:Name="Document"
|
|
||||||
PageWidth="{x:Static local:Constants.DinA4Width}"
|
|
||||||
PageHeight="{x:Static local:Constants.DinA4Height}"
|
|
||||||
PagePadding="{x:Static local:Constants.DinA4Padding}"
|
|
||||||
ColumnWidth="{x:Static local:Constants.DinA4ContentWidth}" />
|
|
||||||
</FlowDocumentScrollViewer>
|
|
||||||
|
|
||||||
<DocumentViewer x:Name="Viewer">
|
<DocumentViewer x:Name="Viewer">
|
||||||
<DocumentViewer.Resources>
|
<DocumentViewer.Resources>
|
||||||
<Style TargetType="{x:Type DocumentViewer}">
|
<Style TargetType="{x:Type DocumentViewer}">
|
||||||
|
|||||||
+13
-231
@@ -6,8 +6,6 @@ using System.Runtime.CompilerServices;
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Controls.Primitives;
|
using System.Windows.Controls.Primitives;
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using UCalc.Annotations;
|
using UCalc.Annotations;
|
||||||
using UCalc.Controls;
|
using UCalc.Controls;
|
||||||
using UCalc.Data;
|
using UCalc.Data;
|
||||||
@@ -86,242 +84,26 @@ namespace UCalc
|
|||||||
|
|
||||||
private void Preview()
|
private void Preview()
|
||||||
{
|
{
|
||||||
Document.Blocks.Clear();
|
|
||||||
|
|
||||||
foreach (var item in TenantMenuItems)
|
|
||||||
{
|
|
||||||
if (!item.Selected)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = BillingCalculator.CalculateForTenant(Billing, item.Tenant);
|
|
||||||
PreviewForSingleTenant(item.Tenant, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
_document?.Dispose();
|
_document?.Dispose();
|
||||||
_document = new PrintableDocument(Document);
|
|
||||||
|
_document = new PrintableDocument(
|
||||||
|
Billing,
|
||||||
|
TenantMenuItems.Where(item => item.Selected).Select(item => item.Tenant)
|
||||||
|
);
|
||||||
_document.PreviewIn(Viewer);
|
_document.PreviewIn(Viewer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddLineBreaks(TableRowGroup rowGroup, int count)
|
|
||||||
{
|
|
||||||
var row = new TableRow();
|
|
||||||
rowGroup.Rows.Add(row);
|
|
||||||
|
|
||||||
var cell = new TableCell {ColumnSpan = 2};
|
|
||||||
row.Cells.Add(cell);
|
|
||||||
cell.Blocks.Add(new Paragraph(new Run(new string('\n', count - 1))
|
|
||||||
{FontSize = Constants.PrintNewlineFontSize}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void AddText(TableRowGroup rowGroup, string text, double? fontSize = null,
|
|
||||||
bool alignRight = false)
|
|
||||||
{
|
|
||||||
var row = new TableRow();
|
|
||||||
rowGroup.Rows.Add(row);
|
|
||||||
|
|
||||||
var cell = new TableCell {ColumnSpan = 2};
|
|
||||||
row.Cells.Add(cell);
|
|
||||||
|
|
||||||
if (alignRight)
|
|
||||||
{
|
|
||||||
cell.TextAlignment = TextAlignment.Right;
|
|
||||||
}
|
|
||||||
|
|
||||||
var paragraph = new Paragraph(new Run(text));
|
|
||||||
cell.Blocks.Add(paragraph);
|
|
||||||
|
|
||||||
if (fontSize != null)
|
|
||||||
{
|
|
||||||
paragraph.FontSize = fontSize.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PreviewForSingleTenant(Tenant tenant, TenantCalculationResult result)
|
|
||||||
{
|
|
||||||
var section = new Section {BreakPageBefore = true, FontSize = Constants.PrintDefaultFontSize};
|
|
||||||
Document.Blocks.Add(section);
|
|
||||||
|
|
||||||
var table = new Table {CellSpacing = 0};
|
|
||||||
section.Blocks.Add(table);
|
|
||||||
table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)});
|
|
||||||
table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)});
|
|
||||||
|
|
||||||
var rowGroup = new TableRowGroup();
|
|
||||||
table.RowGroups.Add(rowGroup);
|
|
||||||
|
|
||||||
void AddLineBreaks(int count)
|
|
||||||
{
|
|
||||||
PrintWindow.AddLineBreaks(rowGroup, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddText(string text, double? fontSize = null, bool alignRight = false)
|
|
||||||
{
|
|
||||||
PrintWindow.AddText(rowGroup, text, fontSize, alignRight);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddCost(string name, decimal amount, bool isLast = false)
|
|
||||||
{
|
|
||||||
var row2 = new TableRow();
|
|
||||||
rowGroup.Rows.Add(row2);
|
|
||||||
|
|
||||||
if (isLast)
|
|
||||||
{
|
|
||||||
row2.Background = Brushes.LightGray;
|
|
||||||
}
|
|
||||||
|
|
||||||
var cell2 = new TableCell
|
|
||||||
{BorderBrush = Brushes.Gray, BorderThickness = new Thickness(1, 1, 0, isLast ? 1 : 0)};
|
|
||||||
row2.Cells.Add(cell2);
|
|
||||||
|
|
||||||
cell2.Blocks.Add(new Paragraph(new Run(name)) {Padding = new Thickness(6)});
|
|
||||||
|
|
||||||
cell2 = new TableCell
|
|
||||||
{
|
|
||||||
BorderBrush = Brushes.Gray, BorderThickness = new Thickness(1, 1, 1, isLast ? 1 : 0),
|
|
||||||
TextAlignment = TextAlignment.Right
|
|
||||||
};
|
|
||||||
row2.Cells.Add(cell2);
|
|
||||||
|
|
||||||
cell2.Blocks.Add(new Paragraph(new Run($"{amount.CeilToString()} €")) {Padding = new Thickness(6)});
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddTextLeftRight(string leftText, string rightText)
|
|
||||||
{
|
|
||||||
var row2 = new TableRow();
|
|
||||||
rowGroup.Rows.Add(row2);
|
|
||||||
|
|
||||||
var cell2 = new TableCell();
|
|
||||||
row2.Cells.Add(cell2);
|
|
||||||
|
|
||||||
cell2.Blocks.Add(new Paragraph(new Run(leftText)));
|
|
||||||
|
|
||||||
cell2 = new TableCell
|
|
||||||
{
|
|
||||||
TextAlignment = TextAlignment.Right
|
|
||||||
};
|
|
||||||
row2.Cells.Add(cell2);
|
|
||||||
|
|
||||||
cell2.Blocks.Add(new Paragraph(new Run(rightText)));
|
|
||||||
}
|
|
||||||
|
|
||||||
AddTextLeftRight(
|
|
||||||
$"{Billing.Landlord.Name}\n{Billing.Landlord.Address.Street} {Billing.Landlord.Address.HouseNumber}\n{Billing.Landlord.Address.Postcode} {Billing.Landlord.Address.City}\nTelefon: {Billing.Landlord.Phone}{(string.IsNullOrEmpty(Billing.Landlord.MailAddress) ? "" : $"\nEmail: {Billing.Landlord.MailAddress}")}",
|
|
||||||
DateTime.Now.ToString(Constants.DateFormat));
|
|
||||||
|
|
||||||
AddLineBreaks(2);
|
|
||||||
|
|
||||||
AddText(
|
|
||||||
$"{tenant.Salutation.AsString()} {tenant.Name}\n{Billing.House.Address.Street} {Billing.House.Address.HouseNumber}\n{Billing.House.Address.Postcode} {Billing.House.Address.City}");
|
|
||||||
|
|
||||||
AddLineBreaks(4);
|
|
||||||
|
|
||||||
AddText($"{tenant.Salutation.AsString()} {tenant.Name}");
|
|
||||||
|
|
||||||
AddLineBreaks(1);
|
|
||||||
|
|
||||||
AddText(
|
|
||||||
$"Nebenkostenabrechnung vom {Billing.StartDate.ToString(Constants.DateFormat)} zum {Billing.EndDate.ToString(Constants.DateFormat)}",
|
|
||||||
Constants.PrintSubjectFontSize);
|
|
||||||
|
|
||||||
AddLineBreaks(1);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(tenant.CustomMessage1))
|
|
||||||
{
|
|
||||||
AddText(tenant.CustomMessage1);
|
|
||||||
|
|
||||||
AddLineBreaks(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var (cost, costResult) in result.Costs)
|
|
||||||
{
|
|
||||||
AddCost(cost.Name, costResult.TotalAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
AddCost("Zwischensumme", result.SubTotalAmount);
|
|
||||||
AddCost("Bereits gezahlt", tenant.PaidRent);
|
|
||||||
AddCost(result.TotalAmount > 0 ? "Einmalige Nachzahlung" : "Einmalige Rückzahlung", result.TotalAmount,
|
|
||||||
true);
|
|
||||||
|
|
||||||
AddLineBreaks(1);
|
|
||||||
|
|
||||||
if (result.TotalAmount > 0)
|
|
||||||
{
|
|
||||||
AddText(
|
|
||||||
$"Bitte überweisen Sie den einmaligen Betrag von {result.TotalAmount.CeilToString()} € auf das untenstehende Konto.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddText(
|
|
||||||
$"Der einmalige Betrag von {(result.TotalAmount * -1).CeilToString()} € wird in den nächsten Tagen auf Ihr Konto überwiesen.");
|
|
||||||
}
|
|
||||||
|
|
||||||
AddLineBreaks(1);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(tenant.CustomMessage2))
|
|
||||||
{
|
|
||||||
AddText(tenant.CustomMessage2);
|
|
||||||
AddLineBreaks(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
AddText("Kontoverbindung:");
|
|
||||||
AddText($"IBAN: {Billing.Landlord.BankAccount.Iban}");
|
|
||||||
AddText($"BIC: {Billing.Landlord.BankAccount.Bic}");
|
|
||||||
AddText($"Name der Bank: {Billing.Landlord.BankAccount.BankName}");
|
|
||||||
|
|
||||||
AddLineBreaks(2);
|
|
||||||
|
|
||||||
AddText("Mit freundlichen Grüßen");
|
|
||||||
|
|
||||||
if (result.Costs.Any(t => t.Key.DisplayInBill))
|
|
||||||
{
|
|
||||||
PreviewForSingleTenantDetails(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PreviewForSingleTenantDetails(TenantCalculationResult result)
|
|
||||||
{
|
|
||||||
var section = new Section {BreakPageBefore = true, FontSize = Constants.PrintDefaultFontSize};
|
|
||||||
Document.Blocks.Add(section);
|
|
||||||
|
|
||||||
var table = new Table {CellSpacing = 0};
|
|
||||||
section.Blocks.Add(table);
|
|
||||||
table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)});
|
|
||||||
table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)});
|
|
||||||
|
|
||||||
var rowGroup = new TableRowGroup();
|
|
||||||
table.RowGroups.Add(rowGroup);
|
|
||||||
|
|
||||||
void AddLineBreaks(int count)
|
|
||||||
{
|
|
||||||
PrintWindow.AddLineBreaks(rowGroup, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddText(string text, double? fontSize = null, bool alignRight = false)
|
|
||||||
{
|
|
||||||
PrintWindow.AddText(rowGroup, text, fontSize, alignRight);
|
|
||||||
}
|
|
||||||
|
|
||||||
AddText("Details zur Berechnung:");
|
|
||||||
|
|
||||||
AddLineBreaks(1);
|
|
||||||
|
|
||||||
foreach (var (cost, costResult) in result.Costs)
|
|
||||||
{
|
|
||||||
if (!cost.DisplayInBill)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddText(costResult.Details);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPrintClick(object sender, RoutedEventArgs e)
|
private void OnPrintClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_document.Print(
|
_document.Print(
|
||||||
$"MietRechner Abrechnung {Billing.StartDate.ToString(Constants.DateFormat)} - {Billing.EndDate.ToString(Constants.DateFormat)}");
|
$"MietRechner Abrechnung {Billing.StartDate.ToString(Constants.DateFormat)} - {Billing.EndDate.ToString(Constants.DateFormat)}"
|
||||||
|
);
|
||||||
|
|
||||||
|
/*PrintDialog printDialog = new PrintDialog();
|
||||||
|
if (printDialog.ShowDialog() == true)
|
||||||
|
{
|
||||||
|
printDialog.PrintQueue.AddJob("test", "C:\\test.xps", false);
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSelectedTenantChanged(object sender, PropertyChangedEventArgs e)
|
private void OnSelectedTenantChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<ApplicationIcon>logo.ico</ApplicationIcon>
|
<ApplicationIcon>logo.ico</ApplicationIcon>
|
||||||
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
Reference in New Issue
Block a user