fix: Anwesenheitskalender respektiert die von der Vorlage vorgegebene Boxhöhe
CI / build-and-test (push) Waiting to run

Nachdem die Kalender-Breite jetzt an die reale DRAWBOX/FLOWDRAWBOX-Breite
gekoppelt ist, konnte das (korrekt größer werdende) Raster die von der
Vorlage deklarierte Höhe überschreiten - eine DRAWBOX bricht anders als eine
FLOWDRAWBOX nicht automatisch auf Folgeseiten um, überschüssiger Inhalt wird
von QuestTemplateRenderer stillschweigend am unteren Rand abgeschnitten.

StudentAttendanceCalendarDrawingBuilder ermittelt jetzt vorab, wie viele
Wochen die gewählten Monate brauchen, und verkleinert "Größe" automatisch so
weit, dass der Kalender innerhalb der deklarierten Höhe bleibt (nur bei
DRAWBOX/IsFixed - eine FLOWDRAWBOX darf weiterhin frei wachsen, da sie bei
Bedarf auf weitere Seiten fließt statt abzuschneiden).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-17 14:39:45 +02:00
co-authored by Claude Sonnet 5
parent 86a97d91a7
commit 4542f263fc
7 changed files with 104 additions and 49 deletions
@@ -12,8 +12,8 @@ public partial class CreateLetterDialogViewModel : ObservableObject
private readonly Student _student;
private readonly TemplateStore _templates;
private readonly ITemplateRenderer _renderer;
private readonly Func<AttendanceCalendarOptions, float, float, DrawingValue>? _attendanceCalendarFactory;
private readonly Func<AttendanceCalendarOptions, float, float, DrawingValue>? _absenceDayListFactory;
private readonly Func<AttendanceCalendarOptions, float, float, float, DrawingValue>? _attendanceCalendarFactory;
private readonly Func<AttendanceCalendarOptions, float, float, float, DrawingValue>? _absenceDayListFactory;
private readonly Func<AttendanceCalendarOptions, CancellationToken, Task>? _attendanceDataRefresher;
private AttendanceCalendarOptions _attendanceCalendarOptions = new(
new DateOnly(DateTime.Today.Year, DateTime.Today.Month, 1), 1);
@@ -52,8 +52,8 @@ public partial class CreateLetterDialogViewModel : ObservableObject
public CreateLetterDialogViewModel(Student student, TemplateStore templates, ITemplateRenderer renderer,
IGroupMembershipRepository memberships, IGroupRepository groups,
Func<AttendanceCalendarOptions, float, float, DrawingValue>? attendanceCalendarFactory = null,
Func<AttendanceCalendarOptions, float, float, DrawingValue>? absenceDayListFactory = null,
Func<AttendanceCalendarOptions, float, float, float, DrawingValue>? attendanceCalendarFactory = null,
Func<AttendanceCalendarOptions, float, float, float, DrawingValue>? absenceDayListFactory = null,
Func<AttendanceCalendarOptions, CancellationToken, Task>? attendanceDataRefresher = null)
{
_student = student; _templates = templates; _renderer = renderer;
@@ -143,9 +143,11 @@ public partial class CreateLetterDialogViewModel : ObservableObject
_student, SelectedContact?.Model, SelectedGroup?.Model,
DateOnly.FromDateTime((LetterDate ?? DateTimeOffset.Now).LocalDateTime), LetterText, TeacherName,
UsesAttendanceCalendar ? _attendanceCalendarFactory?.Invoke(_attendanceCalendarOptions,
calendarBox.Width, calendarBox.MillimeterScale) : null,
calendarBox.Width, calendarBox.MillimeterScale,
calendarBox.IsFixed ? calendarBox.Height : float.PositiveInfinity) : null,
UsesAbsenceDayList ? _absenceDayListFactory?.Invoke(_attendanceCalendarOptions,
absenceDayListBox.Width, absenceDayListBox.MillimeterScale) : null);
absenceDayListBox.Width, absenceDayListBox.MillimeterScale,
absenceDayListBox.IsFixed ? absenceDayListBox.Height : float.PositiveInfinity) : null);
values["Anrede"] = new TextValue(Anrede); values["Letter.Salutation"] = new TextValue(Anrede);
foreach (var custom in CustomPlaceholders) values[custom.Name] = custom.ToPlaceholderValue();
return values;
@@ -157,7 +159,7 @@ public partial class CreateLetterDialogViewModel : ObservableObject
/// 170mm zurück, wenn keine Vorlage gewählt ist oder die Box nicht gefunden wird.</summary>
private LetterPlaceholderBuilder.DeclaredDrawingBox DeclaredDrawingBox(string placeholderName)
{
var fallback = new LetterPlaceholderBuilder.DeclaredDrawingBox(170, 1);
var fallback = new LetterPlaceholderBuilder.DeclaredDrawingBox(170, float.PositiveInfinity, 1, false);
if (SelectedTemplate is null) return fallback;
try { return LetterPlaceholderBuilder.FindDeclaredDrawingBox(_templates.Load(SelectedTemplate.Model), placeholderName) ?? fallback; }
catch (Exception ex) when (ex is IOException or InvalidDataException or TemplateValidationException) { return fallback; }