Klassenlehrer-Tab: vier Feature-Ideen umgesetzt (ohne Elterngesprächs-PDF)

Offene Entschuldigungen mit Frist (neue Seitenspalten-Karte, sortiert nach
Tagen offen), aggregierte Klassenbuch-Kategorien (Chip-Reihe im
Klassenbuch-Tab), Wochentags-Häufung als dritte Mustererkennungsregel, und
eine Wiedervorlagen-Verknüpfung: ein "+"-Button legt direkt aus der Zeile
eine WorkTask "Eltern kontaktieren" an, und eine dritte Musterregel
verknüpft hohe Jahresfehlquote mit fallendem Mitarbeit-Trend.

ContextMenu auf den Zeilen-Buttons scheiterte an Avalonias
$parent-Vorfahren-Bindings (Popup hängt nicht im normalen visuellen Baum) —
stattdessen zwei Geschwister-Buttons pro Zeile. Elterngesprächs-Blatt als
PDF bewusst zurückgestellt, Konzept noch nicht geschärft.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-27 13:57:09 +02:00
co-authored by Claude Sonnet 5
parent 3f8dab4abd
commit 3f484ce3c8
6 changed files with 537 additions and 7 deletions
@@ -44,6 +44,21 @@
<Style Selector="Button.rosterRow:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AppListRowHoverBrush}"/>
</Style>
<Style Selector="Button.rosterRowAction">
<Setter Property="Width" Value="30"/>
<Setter Property="Height" Value="48"/>
<Setter Property="Background" Value="{DynamicResource AppListRowBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource AppListRowBorderBrush}"/>
<Setter Property="BorderThickness" Value="0,0,1,1"/>
<Setter Property="Foreground" Value="{DynamicResource AppAccentTextBrush}"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<Style Selector="Button.rosterRowAction:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AppListRowHoverBrush}"/>
</Style>
<Style Selector="Border.sidePanel">
<Setter Property="Background" Value="{DynamicResource AppCardBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource AppCardBorderBrush}"/>
@@ -89,7 +104,13 @@
<!-- Eine Vorlage für beide Roster-Listen (auffällig / übrige): Sie waren Zeichen für Zeichen
identisch und mussten bisher doppelt gepflegt werden. -->
<DataTemplate x:Key="RosterRowTemplate" x:DataType="vm:ClassTeacherRosterRow">
<Button Classes="rosterRow"
<!-- Zwei Geschwister-Controls statt eines ContextMenu auf dem Zeilen-Button: Avalonia löst
$parent-Vorfahrenpfade in einem ContextMenu nicht zuverlässig auf, weil dessen Popup
nicht im normalen visuellen Baum unter dem ItemsControl hängt. Ein separater kleiner
Button daneben bleibt im normalen Baum und kann so ganz regulär auf das ViewModel des
ItemsControl zugreifen. -->
<Grid ColumnDefinitions="*,Auto">
<Button Grid.Column="0" Classes="rosterRow"
Command="{Binding $parent[ItemsControl].((vm:ClassTeacherOverviewViewModel)DataContext).ShowDetailsForStudentCommand}"
CommandParameter="{Binding}">
<Grid ColumnDefinitions="4,42,220,*,150,18">
@@ -127,6 +148,13 @@
<TextBlock Grid.Column="5" Text="" FontSize="18" Opacity="0.7" VerticalAlignment="Center"/>
</Grid>
</Button>
<!-- Quick-Win: "Eltern kontaktieren" als vorbefüllte Wiedervorlage direkt aus der Zeile
anlegen, statt erst ins Aufgaben-Modul zu wechseln und von Hand einzutragen. -->
<Button Grid.Column="1" Classes="rosterRowAction" Content="+"
ToolTip.Tip="Wiedervorlage „Eltern kontaktieren&#8220; anlegen"
Command="{Binding $parent[ItemsControl].((vm:ClassTeacherOverviewViewModel)DataContext).CreateReminderForStudentCommand}"
CommandParameter="{Binding}"/>
</Grid>
</DataTemplate>
</UserControl.Resources>
@@ -369,6 +397,42 @@
</StackPanel>
</Border>
<Border Classes="sidePanel" IsVisible="{Binding HasOpenExcuses}">
<StackPanel Spacing="8">
<TextBlock Text="Offene Entschuldigungen" FontSize="14" FontWeight="SemiBold"/>
<ItemsControl ItemsSource="{Binding OpenExcuses}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:ClassTeacherOpenExcuseRow">
<Grid ColumnDefinitions="*,Auto">
<Button Grid.Column="0" Classes="rosterRow" Padding="6,5"
Command="{Binding $parent[ItemsControl].((vm:ClassTeacherOverviewViewModel)DataContext).ShowDetailsForOpenExcuseCommand}"
CommandParameter="{Binding}">
<Grid ColumnDefinitions="4,*,Auto" Margin="0,2">
<Border Grid.Column="0" CornerRadius="2" Margin="0,1,8,1"
Classes="statusFill" Classes.warning="{Binding !IsOverdue}"
Classes.danger="{Binding IsOverdue}"/>
<StackPanel Grid.Column="1">
<TextBlock Text="{Binding StudentName}" FontSize="12" FontWeight="SemiBold"/>
<TextBlock Text="{Binding DaysOpenLabel}" FontSize="11" Opacity="0.62"/>
</StackPanel>
<TextBlock Grid.Column="2" Text="{Binding DateLabel}" FontSize="11"
Opacity="0.5" VerticalAlignment="Center"/>
</Grid>
</Button>
<Button Grid.Column="1" Classes="rosterRowAction" Content="+"
ToolTip.Tip="Wiedervorlage „Eltern kontaktieren&#8220; anlegen"
Command="{Binding $parent[ItemsControl].((vm:ClassTeacherOverviewViewModel)DataContext).CreateReminderForOpenExcuseCommand}"
CommandParameter="{Binding}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock FontSize="11" Opacity="0.5" IsVisible="{Binding HasOpenExcuseOverflow}">
<Run Text="+"/><Run Text="{Binding OpenExcuseOverflowCount}"/><Run Text=" weitere"/>
</TextBlock>
</StackPanel>
</Border>
<Border Classes="sidePanel" IsVisible="{Binding HasPatternNotices}">
<StackPanel Spacing="8">
<TextBlock Text="Muster erkannt" FontSize="14" FontWeight="SemiBold"/>
@@ -28,7 +28,7 @@
</Style>
</UserControl.Styles>
<Grid RowDefinitions="Auto,Auto,*,Auto" Margin="16" RowSpacing="10">
<Grid RowDefinitions="Auto,Auto,Auto,*,Auto" Margin="16" RowSpacing="10">
<Grid Grid.Row="0" ColumnDefinitions="*,Auto">
<StackPanel>
<TextBlock Text="Klassenbucheinträge" FontSize="22" FontWeight="SemiBold"/>
@@ -58,7 +58,35 @@
</Grid>
</Border>
<Grid Grid.Row="2">
<!-- Nutzer-Feedback: die reine Gesamtzahl der Einträge sagt wenig, eine Aufschlüsselung nach
Kategorie ("Hausaufgaben fehlen: 12× — 5× Ben Schmidt, 3× Ada Müller") ist die eigentlich
interessante Information. Als Chip-Reihe statt eigener Spalte in der Tabelle, damit die
bestehenden Spalten unangetastet bleiben. -->
<Border Grid.Row="2" Classes="filterCard" IsVisible="{Binding HasCategoryAggregates}">
<StackPanel Spacing="6">
<TextBlock Text="Kategorien im Zeitraum" FontSize="12" FontWeight="SemiBold" Opacity="0.7"/>
<ItemsControl ItemsSource="{Binding CategoryAggregates}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:ClassTeacherCategoryAggregateRow">
<Border Background="{DynamicResource AppChipBackgroundBrush}" CornerRadius="5"
Padding="8,4" Margin="0,0,6,6">
<StackPanel Orientation="Horizontal" Spacing="4">
<TextBlock Text="{Binding CategoryName}" FontSize="11" FontWeight="SemiBold"/>
<TextBlock Text="{Binding SummaryLabel}" FontSize="11" Opacity="0.6"/>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
<Grid Grid.Row="3">
<DataGrid ItemsSource="{Binding Entries}" AutoGenerateColumns="False" IsReadOnly="True"
GridLinesVisibility="Horizontal" BorderBrush="{DynamicResource AppCardBorderBrush}" BorderThickness="1"
CanUserResizeColumns="True" CanUserSortColumns="True" RowHeight="46">
@@ -77,6 +105,6 @@
<TextBlock Text="Passe Zeitraum oder Schülerfilter an." FontSize="12" Opacity="0.55"/>
</StackPanel>
</Grid>
<TextBlock Grid.Row="3" Text="{Binding Status}" FontSize="11" Opacity="0.6"/>
<TextBlock Grid.Row="4" Text="{Binding Status}" FontSize="11" Opacity="0.6"/>
</Grid>
</UserControl>