Templates working
This commit is contained in:
		@@ -4,6 +4,7 @@
 | 
			
		||||
             xmlns:local="clr-namespace:WGneu"
 | 
			
		||||
             StartupUri="Windows\MainWindow.xaml"
 | 
			
		||||
             Startup="App_Startup"
 | 
			
		||||
             Exit="App_Exit"
 | 
			
		||||
             xmlns:ui="http://schemas.modernwpf.com/2019">
 | 
			
		||||
    <Application.Resources>
 | 
			
		||||
        <!--<ResourceDictionary>
 | 
			
		||||
 
 | 
			
		||||
@@ -11,9 +11,11 @@ namespace WGneu {
 | 
			
		||||
    public partial class App : Application {
 | 
			
		||||
 | 
			
		||||
        public static bool IsPrintingReady => Documents.Html.IsReady && Documents.Pdf.IsReady;
 | 
			
		||||
        public static System.Windows.Threading.Dispatcher MainDispatcher { get; private set; }
 | 
			
		||||
 | 
			
		||||
        public App() : base() {
 | 
			
		||||
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
 | 
			
		||||
            MainDispatcher = Dispatcher;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void App_Startup(object sender, EventArgs e) {
 | 
			
		||||
@@ -21,6 +23,10 @@ namespace WGneu {
 | 
			
		||||
            Task.Run(() => Documents.Pdf.Init(PrintingReadyChanged));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void App_Exit(object sender, EventArgs e) {
 | 
			
		||||
            Task.Run(() => Documents.Pdf.Close());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void PrintingReadyChanged() {
 | 
			
		||||
            Dispatcher.BeginInvoke(App_PrintingReadyChanged, this, new EventArgs());
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
@using RazorLight
 | 
			
		||||
@inherits TemplatePage<WGneu.Documents.BusinessDocument>
 | 
			
		||||
@model WGneu.Documents.BusinessDocument
 | 
			
		||||
@{ Layout = "Document"; }
 | 
			
		||||
@{ Layout = "Document.cshtml"; }
 | 
			
		||||
 | 
			
		||||
<div class="info-wrapper">
 | 
			
		||||
    <div class="address-wrapper">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
@using RazorLight
 | 
			
		||||
@inherits TemplatePage<WGneu.Documents.BusinessLetter>
 | 
			
		||||
@model WGneu.Documents.BusinessLetter
 | 
			
		||||
@{ Layout = "BusinessDocument"; }
 | 
			
		||||
@{ Layout = "BusinessDocument.cshtml"; }
 | 
			
		||||
 | 
			
		||||
<p>Sehr geehrtes Mitglied,</p>
 | 
			
		||||
<p>nein.</p>
 | 
			
		||||
 
 | 
			
		||||
@@ -8,33 +8,29 @@
 | 
			
		||||
	<title>@Model.Title</title>
 | 
			
		||||
	<meta charset="UTF-8"/>
 | 
			
		||||
    <script>
 | 
			
		||||
        window.finished = false;
 | 
			
		||||
        window.PagedConfig = { auto: navigator.webdriver };
 | 
			
		||||
        window.PagedConfig = { auto: false };
 | 
			
		||||
        if (!navigator.webdriver) {
 | 
			
		||||
            window.addEventListener("beforeprint", async () => {
 | 
			
		||||
                await window.PagedPolyfill.preview();
 | 
			
		||||
                window.finished = true;
 | 
			
		||||
            });
 | 
			
		||||
            window.addEventListener("afterprint", () => {
 | 
			
		||||
                location.reload();
 | 
			
		||||
            });
 | 
			
		||||
            window.addEventListener("beforeprint", async () => { await window.PagedPolyfill.preview(); });
 | 
			
		||||
            window.addEventListener("afterprint", () => { location.reload(); });
 | 
			
		||||
        }
 | 
			
		||||
    </script>
 | 
			
		||||
    <!-- TODO store paged.js locally to avoid using the internet -->
 | 
			
		||||
    <script src="https://unpkg.com/pagedjs/dist/paged.polyfill.js"></script>
 | 
			
		||||
    <link rel="stylesheet" href="style.css" type="text/css"/>
 | 
			
		||||
    <style>
 | 
			
		||||
        @{ await IncludeAsync("style.css"); }
 | 
			
		||||
    </style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <div class="m1"></div>
 | 
			
		||||
    <div class="m2"></div>
 | 
			
		||||
    <div class="m3"></div>
 | 
			
		||||
    <header>@Model.Header</header>
 | 
			
		||||
    <header>@Raw(Model.Header)</header>
 | 
			
		||||
    <div class="footer-wrapper">
 | 
			
		||||
        <div class="pre-footer">
 | 
			
		||||
            <span class="date">@Model.FullDateString</span>
 | 
			
		||||
            <span class="page"></span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <footer>@Model.Footer</footer>
 | 
			
		||||
        <footer>@Raw(Model.Footer)</footer>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="spacing"></div>
 | 
			
		||||
    <div class="main-wrapper">
 | 
			
		||||
 
 | 
			
		||||
@@ -4,17 +4,29 @@ using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Windows;
 | 
			
		||||
 | 
			
		||||
namespace WGneu.Documents {
 | 
			
		||||
    public abstract class Document {
 | 
			
		||||
    public abstract class Document : IDisposable {
 | 
			
		||||
 | 
			
		||||
        private Utils.TemporaryFile? PdfFile = null;
 | 
			
		||||
 | 
			
		||||
        public Document(string title) {
 | 
			
		||||
            Title = title;
 | 
			
		||||
            Header = "Winzergenossenschaft Matzen";
 | 
			
		||||
            Header = "<h1>Winzergenossenschaft Matzen</h1>";
 | 
			
		||||
            Footer = "Winzergenossenschaft für Matzen und Umgebung reg. Gen.m.b.H.";
 | 
			
		||||
            Date = DateTime.Today;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ~Document() {
 | 
			
		||||
            Dispose();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose() {
 | 
			
		||||
            PdfFile?.Dispose();
 | 
			
		||||
            PdfFile = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string Title { get; set; }
 | 
			
		||||
 | 
			
		||||
        public string Header { get; set; }
 | 
			
		||||
@@ -22,24 +34,41 @@ namespace WGneu.Documents {
 | 
			
		||||
        public string Footer { get; set; }
 | 
			
		||||
 | 
			
		||||
        public string FullDateString {
 | 
			
		||||
            get {
 | 
			
		||||
                return Date.ToString("dddd, d. MMMM yyyy");
 | 
			
		||||
            }
 | 
			
		||||
            get => Date.ToString("dddd, d. MMMM yyyy");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public DateTime Date { get; set; }
 | 
			
		||||
 | 
			
		||||
        private async Task<string> Render() {
 | 
			
		||||
            if (this is BusinessLetter bl) {
 | 
			
		||||
                return await Html.CompileRenderAsync("BusinessLetter", bl);
 | 
			
		||||
            if (this is BusinessLetter) {
 | 
			
		||||
                return await Html.CompileRenderAsync("BusinessLetter.cshtml", this);
 | 
			
		||||
            }
 | 
			
		||||
            throw new InvalidOperationException();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<string> Save() {
 | 
			
		||||
            // TODO tempfile
 | 
			
		||||
            await File.WriteAllTextAsync("razor_test.html", await Render());
 | 
			
		||||
            return "";
 | 
			
		||||
        public async Task Generate() {
 | 
			
		||||
            var pdf = new Utils.TemporaryFile(@"C:\Users\Lorenz\Desktop", ".pdf");
 | 
			
		||||
            using (var tmpHtml = new Utils.TemporaryFile(@"C:\Users\Lorenz\Desktop", ".html")) {
 | 
			
		||||
                await File.WriteAllTextAsync(tmpHtml.FilePath, await Render());
 | 
			
		||||
                await Pdf.Convert(tmpHtml.FilePath, pdf.FilePath);
 | 
			
		||||
            }
 | 
			
		||||
            Pdf.UpdateMetadata(pdf.FilePath, Title, "Wizergenossenschaft für Matzen und Umgebung reg. Gen.m.b.H.");
 | 
			
		||||
            PdfFile = pdf;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SaveTo(string pdfPath) {
 | 
			
		||||
            if (PdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet");
 | 
			
		||||
            File.Copy(PdfFile.FilePath, pdfPath);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task Print() {
 | 
			
		||||
            if (PdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet");
 | 
			
		||||
            Pdf.Print(PdfFile.FilePath);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Show() {
 | 
			
		||||
            if (PdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet");
 | 
			
		||||
            Pdf.Show(PdfFile.NewReference(), Title);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,11 +13,11 @@ namespace WGneu.Documents {
 | 
			
		||||
 | 
			
		||||
        public static async Task Init(Action evtHandler) {
 | 
			
		||||
            var e = new RazorLightEngineBuilder()
 | 
			
		||||
                .UseFileSystemProject(@"C:\Users\Lorenz\source\repos\WGneu\WGneu\Documents")
 | 
			
		||||
                .UseFileSystemProject(@"C:\Users\Lorenz\source\repos\WGneu\WGneu\Documents", "")
 | 
			
		||||
                .UseMemoryCachingProvider()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            await e.CompileTemplateAsync("BusinessLetter");
 | 
			
		||||
            await e.CompileTemplateAsync("BusinessLetter.cshtml");
 | 
			
		||||
 | 
			
		||||
            Engine = e;
 | 
			
		||||
            evtHandler();
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,8 @@ using System.Linq;
 | 
			
		||||
using System.Reflection.Metadata.Ecma335;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System.Windows;
 | 
			
		||||
using System.Windows.Shapes;
 | 
			
		||||
using PdfSharp.Pdf.IO;
 | 
			
		||||
using PuppeteerSharp;
 | 
			
		||||
using PuppeteerSharp.Media;
 | 
			
		||||
@@ -27,12 +29,19 @@ namespace WGneu.Documents {
 | 
			
		||||
            evtHandler();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static async Task Convert(string path_html, string path_pdf) {
 | 
			
		||||
        public static async Task Close() {
 | 
			
		||||
            if (Browser == null) return;
 | 
			
		||||
            await Browser.CloseAsync();
 | 
			
		||||
            Browser = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static async Task Convert(string htmlPath, string pdfPath) {
 | 
			
		||||
            if (Browser == null) throw new InvalidOperationException("The puppeteer engine has not been initialized yet");
 | 
			
		||||
            using var page = await Browser.NewPageAsync();
 | 
			
		||||
            await page.GoToAsync("file://" + path_html);
 | 
			
		||||
            await page.WaitForFunctionAsync("() => window.finished");
 | 
			
		||||
            await page.PdfAsync(path_pdf, new() {
 | 
			
		||||
            page.Console += OnConsole;
 | 
			
		||||
            await page.GoToAsync("file://" + htmlPath);
 | 
			
		||||
            await page.EvaluateFunctionAsync("async () => { await window.PagedPolyfill.preview(); }");
 | 
			
		||||
            await page.PdfAsync(pdfPath, new() {
 | 
			
		||||
                PreferCSSPageSize = true,
 | 
			
		||||
                //Format = PaperFormat.A4,
 | 
			
		||||
                DisplayHeaderFooter = false,
 | 
			
		||||
@@ -45,6 +54,10 @@ namespace WGneu.Documents {
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void OnConsole(object sender, ConsoleEventArgs e) {
 | 
			
		||||
            MessageBox.Show(e.Message.Text);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void UpdateMetadata(string path, string title, string author) {
 | 
			
		||||
            using var doc = PdfReader.Open(path);
 | 
			
		||||
            doc.Info.Title = title;
 | 
			
		||||
@@ -52,9 +65,18 @@ namespace WGneu.Documents {
 | 
			
		||||
            doc.Save(path);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void Show(Utils.TemporaryFile file, string title) {
 | 
			
		||||
            App.MainDispatcher.BeginInvoke(() => {
 | 
			
		||||
                var w = new DocumentViewerWindow(title, file);
 | 
			
		||||
                w.Show();
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void Show(string path, string title) {
 | 
			
		||||
            var w = new DocumentViewerWindow(title, path);
 | 
			
		||||
            w.Show();
 | 
			
		||||
            App.MainDispatcher.BeginInvoke(() => {
 | 
			
		||||
                var w = new DocumentViewerWindow(title, path);
 | 
			
		||||
                w.Show();
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void Print(string path) {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using WGneu.Models;
 | 
			
		||||
using System.Windows;
 | 
			
		||||
 | 
			
		||||
namespace WGneu.Documents {
 | 
			
		||||
    class Template {
 | 
			
		||||
@@ -19,9 +20,16 @@ namespace WGneu.Documents {
 | 
			
		||||
            Pdf.Show(ROOT + "test.pdf", "Test-Dokument");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static async void Generate(WgContext c) {
 | 
			
		||||
            var letter = new BusinessLetter("Test Dokument", c.Members.First());
 | 
			
		||||
            var pdf_path = await letter.Save();
 | 
			
		||||
        public static void Generate(WgContext c) {
 | 
			
		||||
            Task.Run(async () => {
 | 
			
		||||
                try {
 | 
			
		||||
                    using var letter = new BusinessLetter("Test Dokument", c.Members.First());
 | 
			
		||||
                    await letter.Generate();
 | 
			
		||||
                    letter.Show();
 | 
			
		||||
                } catch (Exception e) {
 | 
			
		||||
                    MessageBox.Show(e.ToString(), "PDF Generation", MessageBoxButton.OK, MessageBoxImage.Error);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -136,15 +136,15 @@ footer {
 | 
			
		||||
    text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@page {
 | 
			
		||||
@@page {
 | 
			
		||||
    size: A4;
 | 
			
		||||
    margin: 25mm 0 35mm 0;
 | 
			
		||||
    @bottom-center {
 | 
			
		||||
    @@bottom-center {
 | 
			
		||||
        content: element(page-footer);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media screen {
 | 
			
		||||
@@media screen {
 | 
			
		||||
    body, header, .footer-wrapper {
 | 
			
		||||
        width: 210mm;
 | 
			
		||||
    }
 | 
			
		||||
@@ -166,7 +166,7 @@ footer {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media print {
 | 
			
		||||
@@media print {
 | 
			
		||||
    .page::after {
 | 
			
		||||
        content: "Seite " counter(page) " von " counter(pages);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,9 +6,10 @@ using System.Threading.Tasks;
 | 
			
		||||
using System.Windows.Media;
 | 
			
		||||
using System.Windows;
 | 
			
		||||
using System.Windows.Controls;
 | 
			
		||||
using System.IO;
 | 
			
		||||
 | 
			
		||||
namespace WGneu {
 | 
			
		||||
    class Utils {
 | 
			
		||||
    public static class Utils {
 | 
			
		||||
        public static void SetInputChanged(Control input) {
 | 
			
		||||
            input.BorderBrush = Brushes.Orange;
 | 
			
		||||
        }
 | 
			
		||||
@@ -44,5 +45,46 @@ namespace WGneu {
 | 
			
		||||
                throw new ArgumentException("First argument has to be a decimal string");
 | 
			
		||||
            return a.Select(ch => ch - '0').Aggregate((sum, n) => (sum * 10 + n) % b);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public sealed class TemporaryFile : IDisposable {
 | 
			
		||||
            private int Usages = 0;
 | 
			
		||||
            public string FilePath { get; private set; }
 | 
			
		||||
 | 
			
		||||
            public TemporaryFile() : this("") {}
 | 
			
		||||
 | 
			
		||||
            public TemporaryFile(string ext) : this(Path.GetTempPath(), ext) {}
 | 
			
		||||
 | 
			
		||||
            public TemporaryFile(string dir, string ext) {
 | 
			
		||||
                FilePath = Path.Combine(dir, Path.GetRandomFileName() + ext);
 | 
			
		||||
                Usages++;
 | 
			
		||||
                Create();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ~TemporaryFile() {
 | 
			
		||||
                Delete();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public void Dispose() {
 | 
			
		||||
                if (--Usages == 0) {
 | 
			
		||||
                    Delete();
 | 
			
		||||
                    GC.SuppressFinalize(this);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public TemporaryFile NewReference() {
 | 
			
		||||
                Usages++;
 | 
			
		||||
                return this;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private void Create() {
 | 
			
		||||
                using (File.Create(FilePath)) {};
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private void Delete() {
 | 
			
		||||
                if (FilePath == null) return;
 | 
			
		||||
                File.Delete(FilePath);
 | 
			
		||||
                FilePath = null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
        xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
 | 
			
		||||
        xmlns:local="clr-namespace:WGneu.Windows"
 | 
			
		||||
        mc:Ignorable="d"
 | 
			
		||||
        Closed="OnClosed"
 | 
			
		||||
        Title="PDF Ansicht"
 | 
			
		||||
        MinHeight="600" MinWidth="420" Height="750" Width="525">
 | 
			
		||||
    <Grid>
 | 
			
		||||
 
 | 
			
		||||
@@ -14,10 +14,22 @@ using System.Windows.Shapes;
 | 
			
		||||
 | 
			
		||||
namespace WGneu.Windows {
 | 
			
		||||
    public partial class DocumentViewerWindow : Window {
 | 
			
		||||
 | 
			
		||||
        private Utils.TemporaryFile? PdfFile = null;
 | 
			
		||||
 | 
			
		||||
        public DocumentViewerWindow(string title, string path) {
 | 
			
		||||
            InitializeComponent();
 | 
			
		||||
            Title = Title + " - " + title;
 | 
			
		||||
            WebView.Source = new("file://" + path);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public DocumentViewerWindow(string title, Utils.TemporaryFile file) : this(title, file.FilePath) {
 | 
			
		||||
            PdfFile = file;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnClosed(object sender, EventArgs e) {
 | 
			
		||||
            PdfFile?.Dispose();
 | 
			
		||||
            PdfFile = null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user