Ich vermute es fehlt ein Nicht-Null-Wert – was auch immer das bedeuten mag.
Ein "Nicht-Null-Wert" ist ein Wert, der nicht null ist. Du kannst dem Template nicht null zuweisen, aber wo genau das auftritt, sollte dir die Fehlermeldung sagen.
Ansonsten scheint es in deinem Code noch mehrere andere Merkwürdigkeiten zu geben. Wo defininierst du z.B. das Template für "ExpanderHeaderCollapsedType", und warum gibst du als TargetNullValue für einen String-Wert ein "true" an?
Für die Benutzeroberfläche würde ich ein Grid mit SharedSizeGroup in einem ItemsTemplate verwenden. Als Datenmodell hat du eine Auflistung von Wochen verwenden, die eine Auflistung von (jeweils 7) Tagen haben. Die Anzahl der Wochen sollte dabei allerdings nicht statisch sein, weil ein Februar auch hin und wieder mal nur 4 Wochen haben wird.
Daß du keine fertige Lösung verwenden willst, heißt ja nicht, daß du nicht auch in Code von anderen Leuten reinschauen kannst, die das schon mal umgesetzt haben. Kalender wurden schon mehrfach umgesetzt, und der Algorithmus und das Datenmodell basieren meistens auf dem gleichen Prinzip.
Du solltest bei deinem Datenmodell dann halt noch beachten, daß sich Termine über mehrere Tage oder sogar Monate erstrecken können.
Es gibt keine "einzelne Anwendung auf der Soundkarte". Die Soundkarte gibt nur Audio-Signale aus. Die Signale von den einzelnen Anwendungen werden im Betriebssystem gemischt, und dann auf der Soundkarte ausgegeben. Wenn du die Lautstärke einer bestimmten Anwendung messen willst, mußt du die Signale vor der Mischung abgreifen. Und dazu gibt es die genannte Schnittstelle.
Es gibt für die API eine Dokumentation und Quellcode-Beispiele. Sicherlich nicht für dein spezielles Problem, aber mit ein bißchen Anstrengung findest du dafür die Lösung.
Du solltest dir auch mal [Artikel] MVVM und DataBinding anschauen. Wenn man DataBinding verwendet, dann kann man weitestgehend auf Events verzichten, und man muß sich auch keine Sorgen machen, in welchem Thread was ausgeführt wird.
Wenn du das beruflich machst, solltest du dich mal mit den Grundlagen der Software-Entwicklung auseinandersetzen. Sonst wirst du immer wieder von einem "kuriosen" Problem zum anderen stolpern.
Ich hab mich entschieden, die PDF-Erstellung mit XSL-FO in Kombination mit Razor umzusetzen.
XSL-FO ist als Format genau dafür geschaffen worden, Druckdokumente zu erstellen, und ist leicht zu verstehen, wenn man mit HTML und CSS Erfahrung hat. Hier gibt es die Doku und ein paar Tutorials. Und mit Razor als Template-Engine kann man aus Daten einfach Reports erstellen, das kenne ich noch von ASP.NET MVC.
So kann man damit ein Template kompilieren und auswerten:
// Compiling is only done once
IRazorEngine razorEngine = new RazorEngine();
var compiledTemplate = await razorEngine.CompileAsync<RazorEngineTemplateBase<TModel>>(templateContent)
.ConfigureAwait(false);
// Resolving a FO template for the specified model
string foTemplateResult = await compiledTemplate.RunAsync(instance =>
{
instance.Model = model;
}).ConfigureAwait(false);
Für das Rendern des Templates in eine PDF verwende ich das Package Fonet.Standard (Source Code, Wiki). Das funktioniert soweit sehr gut. Ein paar Einschränkungen muß man dafür allerdings hinnehmen:
Bilder mit transparentem Hintergrund werden nicht unterstützt
SVGs werden nicht unterstützt (aber andere Vektor-Formate)
Tabellen mit automatischen Spaltenbreiten sind nicht möglich
Es können nur Schriftarten verwendet werden, die im Betriebssystem installiert sind
So funktioniert das Rendern der PDF:
var foNetDriver = FonetDriver.Make();
foNetDriver.Options = /* Set PDF options */;
foNetDriver.CloseOnExit = false; // Don't close stream after rendering
foNetDriver.ImageHandler = /* Set callback to load images from files or resources */;
foNetDriver.Render(foInputStream, pdfOutputStream);
Insgesamt sind das ca. 100 Zeilen Code in einer .NET-Standard-Bibliothek, die wir zukünftig für Web- und Desktop-Anwendungen verwenden können.
Wenn die Schema-Datei im gleichen Verzeichnis liegt wie die Template-Dateien, bekommt man in Visual Studio sogar Intellisense für XSL-FO.
Das mag vielleicht ein bißchen over-engineered aussehen, ist aber wesentlich besser als DevExpress- und Crystal-Reports oder die Konvertierung von HTML- oder Word-Dateien.
Ich glaube, das ist das, wonach ich gesucht hatte. Eine Auszeichnungssprache für Druckdokumente. Ein erster Test hat gezeigt, daß es macht, was es soll. Jetzt werde ich mal ein komplexeres Layout umsetzen.
ich bin auf der Suche nach einer Möglichkeit, PDF-Dateien aus Templates + Daten zu erstellen. Diese Dateien sollen mehrseitig, möglichst barrierefrei zugänglich sein, und mit Seiten-Headern und -Footern ausgestattet sein. Das ganze soll in einer ASP.NET Core Web-Anwendung unter Linux laufen.
Bisher haben wir dafür das Reporting-Tool von DevExpress verwendet. Dafür hat man das Layout in einem proprietären Editor zusammengefrickelt, und dann die Daten per "DataBinding" in das Layout gefrickelt. Im Zuge der Umstellung auf .NET 5 wollen wir davon wegmigrieren.
Ich war ein bißchen ernüchtert, nachdem ich diesen Artikel gelesen hatte: Creating A PDF In .NET Core. Jemand hat dort die aktuellen (2019) Möglichkeiten evaluiert. Die Kommentare darunter sind auch sehr aufschlußreich. Offenbar gibt es kein Tool von kostenlos bis extrem teuer, das unsere Anforderungen abdeckt. Entweder gibt es keine Lösung für .NET Core, oder es läuft nicht unter Linux, oder es werden bei Seitenumbrüchen die Hälfte der letzten Zeile auf Seite 1 und die andere Hälfte der Zeile auf Seite 2 gedruckt, was für professionelle Dokumente natürlich nicht akzeptabel ist.
Und alle Bibiotheken, die kein Templating unterstützen, wo man also jedes Element selbst auf der Seite positionieren muß, kommt für unsere Zwecke nicht in Frage.
Meine erste Idee war daher, ein HTML- bzw. Razor-Template zu verwenden, und das dann in einem Headless-Chromium-Browser auf dem Server in ein PDF zu rendern. Aber leider eignet sich HTML nicht als Druckformat, denn sich auf allen Seiten wiederholende Header und Footer werden z.B. derzeit nur mit sehr häßlichen Workarounds unterstützt.
Eine andere Idee ist, mit Hilfe des Open XML SDK ein Word-Dokument zu erstellen, und das dann mittels LibreOffice per Kommandozeile in ein PDF zu konvertieren. Das scheint die einzige Möglichkeit zu sein, die alle unsere Anforderungen abdeckt. Aber vom Aufwand her übertrifft das noch das Erstellen von DevExpress-Reports.
Hat jemand etwas ähnliches schon im Einsatz? Oder gibt es andere Ideen?
Wenn du System.Reactive.Linq verwendest, kannst du die einfach die Events als Observable abonnieren und die Observable.Throttle-Methode verwenden. In der Doku gibt es ein Beispiel.
Die WebClient-Methoden sind aber schon asynchrone Methoden, die hast du in deinem Beispiel nicht. Du willst Code parallel ausführen. Dafür reicht im einfachsten Fall ein Aufruf von Parallel.ForEach.
Ich empfehle, dir mal die Doku zu Tasks, asynchroner Programmierung und der Parallel-Klasse bzw. PLinq durchzulesen, damit du verstehst, worum es geht. Asynchrone Programmierung und parallele Programmierung sind zwei unterschiedliche Sachen.
Ich weiß auch nicht, wie man dir da weiterhelfen sollte. Normalerweise ist die Herangehensweise immer die gleiche:
Zuerst erstellt man ein Datenmodell, mit dem man alle Funktionen und Berechnungen durchführen kann, die für das Programm benötigt werden
Dann implementiert man die Funktionen mit Hilfe des Datenmodells
Dann testet man alle Funktionen mit Hilfe von Unit-Tests
Und zum Schluß erstellt man eine Benutzeroberfläche für das Programm.
Du willst die ersten Schritte auslassen, und mit dem letzten Schritt beginnen. Dann kommst du von einem Problem zum nächsten, und von einem Workaround zum anderen, und keiner kann mehr deine Herangehensweise nachvollziehen, oder deinen Code verstehen, um dir da weiterhelfen zu können. Überleg dir nur mal, an wie vielen Stellen du deinen Code anpassen müßtest, wenn sich die Spaltenbreite im DataGrid von 50 auf 100 Pixel ändern würde.
Niemand wird dich davon abhalten, so weiterzumachen. Aber dann kannst du halt auch keine Hilfe im Forum erwarten, weil niemand so arbeiten würde. Mit dem Debugger könntest du dich von Rechenschritt zu Rechenschritt hangeln, und nachvollziehen, was dein Code macht, und dann berichtigen. Siehe dazu [Artikel] Debugger: Wie verwende ich den von Visual Studio?
Empfehlen würde ich allerdings eine etwas strukturiertere Herangehensweise, und erstmal ein geeignetes Datenmodell zu erstellen. Dann kannst du deine Berechnungen so implementieren, daß sie für dich (und andere) auch in ein paar Wochen oder Monaten noch nachvollziehbar sind.
Mit foreach kann man jede Auflistung durchlaufen, die das IEnumerable- bzw. das generische IEnumerable<T>-Interface implementiert. Und ObservableCollection<T> implementiert IEnumerable<T>.
Die Eigenschaft VersandDaten, die du durchlaufen willst, ist aber vom Typ MainViewModel.VersandDaten, und diese implementiert nicht IEnumerable, das sagt die Fehlermeldung.
PS:
Zitat
"Wie poste ich richtig" ist manchmal schwer das Thema in den wenigen Worten zu formulieren...
Die Fehlermeldung und den entsprechenden Code-Ausschnitt zu posten, ist schon irgendwie notwendig, um dir in einem Forum weiterhelfen zu können.
Die vorgeschlagenen Lösungen sind im Grunde nur Workarounds für ein Problem, das es ohne DataGrid nicht gäbe.
Das Problem kommt daher, daß du in der View das DataGrid verwendest, und das dann wieder im ViewModel brauchst, um die Textblöcke zu positionieren.
Ein DataGrid braucht man, wenn man große Mengen an Daten anzeigen, sortieren, gruppieren usw. muß. Es ist nicht dafür gedacht, ein Layout zu erstellen. Besonders nicht, wenn man etwas außerhalb des DataGrids positionieren möchte, wie es bei dir der Fall ist.
Bei dir sind es offenbar wenige Daten, die in einem gleichmäßigen Raster dargestellt werden sollen. Und dann sollen in dem gleichen Raster zusätzliche Textblöcke eingefügt werden.
Dafür gibt es schon ein Steuerelement, nämlich das Grid. Und im ViewModel kannst du alles genauso konfigurieren, wie du es brauchst, und dann an die View binden. Siehe dazu meine vorherigen Beiträge.
Lies dir nochmal die Antworten oben und die verlinkten Artikel durch, dann wird es vielleicht klarer, was gemeint ist.
Ich würde nach wie vor davon abraten, dafür ein DataGrid zu verwenden. Das macht die Sache nur unnötig kompliziert.
Zitat von CombatKarl
Aber wie stelle ich denn fest, ob Start -und Endpunkte sich überschneiden ??
Das sind doch am Ende nur (wenn alles korrekt implementiert ist) zwei Vergleiche.
Wenn ein Endpunkt oder ein Startpunkt eines Panels größer als der Startpunkt und kleiner als der Endpunkt eines anderen Panels ist, dann überschneiden sie sich.
Im ViewModel kriege ich ja das ListView z.B. in einer foreach Schleife mehrmals instanziiert
Dann verwendest du ja kein Binding. Nimm stattdessen lieber ein ItemsControl, das du an eine ObservableCollection bindest. So wie in dem Beispiel von Wilfried, oder in den Beispielen in [Artikel] MVVM und DataBinding
Wie könnte denn deiner Meinung nach eine solche Klasse gestaltet sein & welche Properties wären denn notwendig ?
Ich meine eine Datenstruktur, die es dir ermöglicht, deine Anwendungslogik zu implementieren. Hier also ein regelmäßiges Grid aus Zeilen und Spalten, um Zellen zu selektieren und mit Inhalten zu befüllen. Das hat ersteinmal nichts mit der Benutzeroberfläche zu tun, siehe dazu [Artikel] Drei-Schichten-Architektur
Mit dieser Datenstruktur kannst du dann die Positionen, Größen und Inhalte der Zellen direkt an die View binden, z.B. an ein Grid oder (wie vonTh69 vorgeschlagen) an eine Canvas.
Der Unterschied zwischen Grid und Canvas wäre, daß ein Grid nur regelmäßige Zeilen und Spalten besitzt, und Elemente in einem Canvas völlig frei positionierbar sind.
Aktuell komme ich bereits an dem Punkt nicht weiter, wie der Code zu gestalten ist, wenn die Textblöcke unterhalb meines Datagrids erstellt & positioniert werden.
Ich wüßte auch nicht, wie man das so implementieren würde. Deshalb hatte ich Vorschläge gemacht, wie es funktionieren könnte.