Alle Projekte referenzieren VBK_VDV454_ImportCore. Die UI nutzt zusätzlich DevExpress 24.1.14 (Wpf.Grid, Mvvm, Themes).
Das Hauptfenster verwendet einen DockLayoutManager mit folgender Aufteilung:
Abb. 1: Fahrten-Ansicht — Steuerung-Panel (links), Fahrten-Master-Grid (oben), Fahrt-Detail-Grid (unten)
| Bereich | Komponente | Beschreibung |
|---|---|---|
| Links | LayoutPanel (500px, fixiert) | Steuerung mit Tabs: Betriebstage, Import, Einstellungen |
| Oben rechts | GridControl + TableView | Fahrten-Master-Grid (ItemsSource: FahrtenCollection) |
| Unten rechts | GridControl + dynamische Spalten | Fahrt-Detail-Grid mit Haltestellen als Spalten, Telegramme als Zeilen |
| Tab-Leiste | DocumentGroup | Umschaltung zwischen [Fahrten], [Formation] und [Fahrt-Detail] |
Quelle: MainWindow.xaml
| Spalte | Binding (FieldName) | Typ | Beschreibung |
|---|---|---|---|
| Betriebstag | Betriebstag | DateTime | Datum des Betriebstages (Format: d = kurzes Datum) |
| Anzahl Fahrten | AnzahlFahrten | int | Gesamtanzahl importierter Fahrten |
| Importiert am | ImportTime | DateTime | Zeitpunkt des Imports (Format: g = Datum + Uhrzeit) |
| Import fehlerhaft | HasErrors | bool | Checkbox — true wenn Import-Fehler auftraten |
| Fehlertext | ErrorMessage | string | Fehlermeldung (leer bei fehlerfreiem Import) |
Datenquelle: ImportedBetriebstage (List<ImportInfoModel>), geladen via IImportService.FindImportedBetriebstage(rootFolder).
Selektion eines Betriebstages triggert GetFahrtenAsync() im ViewModel.
Manueller Import-Workflow:
PrepareImportCommand → IImportService.InitImport()
ExecuteImportCommand → IImportService.ExecuteImport()
Data/{YYYY}/{MM}/{DD}/| Einstellung | Binding | Persistenz |
|---|---|---|
| Daten-Ordner | Settings_DataFolder | WPF Settings.Default |
| Temporärer Import-Ordner | Settings_TempImportFolder | WPF Settings.Default |
| Standard Import-Ordner | Settings_DefaultImportFolder | WPF Settings.Default |
| Global-ID anzeigen | ShowGlobalId | Session (nicht persistiert) |
Zeigt alle Fahrten eines ausgewählten Betriebstages. Selektion einer Zeile lädt das Fahrt-Detail-Grid.
| Spalte | FieldName | Typ | Sichtbarkeit |
|---|---|---|---|
| Startzeit | Startzeit | DateTime? | Immer |
| Endzeit | Endzeit | DateTime? | Immer |
| Fahrt Bezeichner | FahrtBezeichner | string | Immer |
| Fahrt Nr | FahrtNr | int | Immer |
| Linien Text | LinienText | string | Immer |
| Richtungs ID | RichtungsID | string | Immer |
| Umlauf ID | UmlaufID | string | Immer |
| Betreiber | Betreiber | string | Immer |
| Start Halt Text | StartHaltText | string | Immer |
| Linien-ID | LinienID | string | Nur bei ShowGlobalId = true |
| Start Halt ID | StartHaltID | string | Nur bei ShowGlobalId = true |
| End Halt ID | EndHaltID | string | Nur bei ShowGlobalId = true |
Die fokussierte Zeile wird fett und mit grauem Hintergrund (#eeeeee) hervorgehoben (FocusedRowStyle).
Modell: FahrtModel (VBK_VDV454_Import_UI/Models/FahrtModel.cs)
Zeigt die zeitliche Entwicklung einer einzelnen Fahrt. Zeilen = VDV454-Datenabrufe (zeitlich aufsteigend), Spalten = Haltestellen (in Reihenfolge der Fahrt).
| Spalte | FieldName | Template | Beschreibung |
|---|---|---|---|
| Zeitstempel | Zeitstempel | ZeitstempelColumnTemplate | Zeitpunkt des Datenabrufs. Format: HH:mm:ss:ffff. Hintergrund: Khaki, fett. |
| K. (Komplettfahrt) | Komplettfahrt | KomplettfahrtColumnTemplate | Checkbox (bool). Gibt an, ob der Datensatz eine vollständige Fahrt enthält. |
| P. (Prognose fortlaufend) | PrognoseFortlaufend | PrognoseFortlaufendColumnTemplate | Checkbox (bool). Fortlaufender Prognose-Status. Wird aus PrognoseMoeglich fortgeschrieben — bleibt true solange PrognoseMoeglich true ist, wird false wenn PrognoseMoeglich auf false wechselt. |
| P. (Prognose möglich) | PrognoseMoeglich | PrognoseMoeglichColumnTemplate | Checkbox (bool?, dreistufig: true/false/null). Aktueller Prognose-Status aus VDV454-Datensatz. |
Für jede Haltestelle der Fahrt wird dynamisch eine Spalte erzeugt. Die Spalten verwenden DefaultColumnTemplate und zeigen in jeder Zelle ein HstCell-Objekt.
HstCell)| Element | Property | Position | Darstellung |
|---|---|---|---|
| Abfahrtszeit | ZeitAbfahrt |
Rechts, vertikal zentriert | Format HH:mm. Wenn PrognoseFortlaufend aktiv: zeigt IstAbfahrtPrognose, sonst Abfahrtszeit. |
| Prognose-Statuslinie | IstAbfahrtPrognoseStatus |
Rechter Rand, vertikale Linie | Farbige Linie (2px breit, 22px hoch):
prognose = Blau
real = Grün
geschaetzt = Orange
unbekannt = Rot
|
| Besetztgrad-Quadrat | Besetztgrad |
Rechts oben (5×5px Rechteck) | Farbiges Quadrat:
schwach besetzt
normal besetzt
stark besetzt
unbekannt
|
| Einsteigeverbot | Einsteigeverbot |
Links oben | Buchstabe E (rot, 10pt) wenn true |
| Aussteigeverbot | Aussteigeverbot |
Links unten | Buchstabe A (rot, 10pt) wenn true |
| Durchfahrt | Durchfahrt |
Links mitte | Buchstabe D (rot, 10pt) wenn true |
ExpandoObject-Instanzen dynamisch erzeugt. Jede Zeile ist ein ExpandoObject, dessen Keys die Haltestellen-IDs sind und dessen Values jeweils ein HstCell-Objekt. Der HstColumnTemlateSelector wählt das passende Template je nach FieldName.
Template-Logik: MainWindow.xaml (Zeilen 169–300) | Datenaufbau: FahrtModel.FromOutputFahrtModel()
Der Tab „Fahrt-Detail“ erscheint nur, wenn eine Fahrt mehrere Telegramm-Nummern (Komplettfahrten) besitzt (HasMultipleFahrten = true). Er zeigt jede Telegramm-Nummer als separates Grid untereinander.
Abb. 2: Fahrt-Detail Tab — Mehrere Telegramm-Blöcke mit Checkbox-Steuerung (oben) und Detail-Grids (unten)
Das Panel ist an HasMultipleFahrten gebunden:
Visibility="{Binding HasMultipleFahrten, Converter={BooleanToVisibilityConverter}}"
HasMultipleFahrten wird im ViewModel auf true gesetzt, wenn für den gewählten FahrtBezeichner mehr als eine Fahrt (Telegramm) existiert.
┌────────────────────────────────────────────────────────────┐
│ [☑] 1 [☑] 2 [ ] 3 [ ] 4 [☑] 5 S11 * de:kvv:00S11 * 56010-5048 │
│ (LinienText * LinienID * Bezeichner) │
├────────────────────────────────────────────────────────────┤
│ GroupBox "1" │
│ GridControl (HstColumnTemplateSelector, MaxHeight=600) │
│ → ColumnsSource: FahrtenItem.Fahrten[0].HstColumns │
│ → ItemsSource: FahrtenItem.Fahrten[0].FahrtAbrufenItems │
├────────────────────────────────────────────────────────────┤
│ GroupBox "2" │
│ GridControl (gleicher Aufbau) │
├────────────────────────────────────────────────────────────┤
│ GroupBox "5" (3, 4 ausgeblendet via IsVisible) │
│ GridControl (gleicher Aufbau) │
└────────────────────────────────────────────────────────────┘
| Element | Typ / Binding | Beschreibung |
|---|---|---|
| Telegramm-Checkboxen | FlowLayoutControlItemsSource: FahrtenItem.Fahrten |
Horizontale Reihe von CheckEdit-Elementen. Content: FahrtNr, IsChecked: IsVisible. Steuert die Sichtbarkeit der einzelnen GroupBoxen. |
| Fahrt-Info (blau) | TextBlock (Foreground: Blue, Bold) |
Zeigt LinienText * LinienID * FahrtBezeichner der aktuell gewählten Fahrt. |
| Telegramm-Blöcke | FlowLayoutControl (Vertical)ItemsSource: FahrtenItem.Fahrten |
Je FahrtModel eine GroupBox mit Header = FahrtNr. Visibility gebunden an IsVisible. |
| Detail-Grids | GridControlMaxHeight: 600 |
Identischer Aufbau wie das Fahrt-Detail-Grid im Fahrten-Tab. Nutzt denselben HstColumnTemplateSelector mit dynamischen Haltestellen-Spalten. |
Beim Klick auf eine Fahrt im Fahrten-Grid:
GetSelectedFahrtAllesAsync() lädt alle Fahrten mit gleichem FahrtBezeichnerFahrtNr aufsteigendFahrtModel in FahrtenItem.Fahrten gespeichertIsVisible = true, restliche ebenfalls (alle Checkboxen initial aktiviert)HasMultipleFahrten wird true wenn Fahrten.Count > 1 → Tab wird sichtbarSingleFahrt wird auf die Fahrt mit der selektierten FahrtNr gesetzt (für das Detail-Grid im Fahrten-Tab)FahrtenItem.SingleFahrt). Der Fahrt-Detail-Tab zeigt alle Telegramme einer Fahrt als separate, ein-/ausblendbare Blöcke. Die Grid-Konfiguration (Templates, Spalten, Formatierung) ist identisch.
Quelle: MainWindow.xaml (Zeilen 870–960) | ViewModel: MainWindowViewModel.GetSelectedFahrtAllesAsync()
Zeigt Fahrten aufgeschlüsselt nach Fahrzeugen in der Zugformation. Die Ansicht hat zwei umschaltbare Detail-Modi: Belegungsgrad und Barrierefreiheit.
Abb. 3: Formation-Ansicht — Modus Barrierefreiheit (Checkbox „Belegungs-Grad“ deaktiviert)
Abb. 4: Formation-Ansicht — Modus Belegungsgrad (Checkbox „Belegungs-Grad“ aktiviert)
FahrtModelMitFahrzeugJede Zeile = eine Kombination aus Fahrt + Fahrzeug. Erbt von FahrtModel und ergänzt fahrzeugspezifische Felder.
| Spalte (Header) | FieldName | Typ | Fixed | Beschreibung |
|---|---|---|---|---|
| Startzeit | Startzeit | DateTime? | Left | Fahrtbeginn (Format: g) |
| Endzeit | Endzeit | DateTime? | Left | Fahrtende (Format: g) |
| Fahrt Bezeichner | FahrtBezeichner | string | Left | Eindeutige Fahrt-Kennung |
| Telegramm Nr | FahrtNr | int | — | Header weicht ab: „Telegramm Nr“ statt „Fahrt Nr“ |
| Richtungs ID | RichtungsID | string | — | Fahrtrichtung |
| Umlauf ID | UmlaufID | string | — | Umlauf-Zuordnung |
| Betreiber | Betreiber | string | — | Verkehrsunternehmen |
| Fahrzeug Id | FahrzeugId | string | — | Eindeutige Fahrzeug-Kennung (z.B. V661-1556) |
| Fahrzeug Typ | FahrzeugTyp | string | — | Fahrzeugtyp-Bezeichnung (z.B. 111, 114) |
| Sitzplätze | Sitzplätze | string | — | Anzahl Sitzplätze (z.B. 42, 49) |
| Stehplätze | Stehplätze | string | — | Anzahl Stehplätze (z.B. 70, 99) |
| Gruppen-ID | GruppenId | string | — | Fahrzeuggruppen-Bezeichner (Zugverband) |
| Gruppen-Ziel | GruppenZiel | string | — | Zielhalt der Fahrzeuggruppe |
| Gruppen-Start | GruppenStart | string | — | Starthalt der Fahrzeuggruppe |
| (versteckt) | FahrtId | string | — | Internes Mapping-Feld ({FahrtBezeichner}_{FahrtNr}_{Startzeit}) |
Optionale Spalten (nur bei ShowGlobalId = true): LinienID, StartHaltID, EndHaltID
ShowBelegungsGradDer Detail-Bereich hat einen umschaltbaren Header: „Belegungsgrad“ oder „Barrierefreiheit“, gesteuert durch die Checkbox „Belegungs-Grad“.
ColumnBands)Das Detail-Grid nutzt GridControlBand zur Gruppierung der Spalten:
Band "Info" (Fixed=Left)
└── Zeitstempel (HH:mm:ss:ffff)
└── Fzg Position (int)
Band "{StartHst} - {EndHst}" ← Je Fahrtabschnitt ein Band
└── Haltestelle 1 (FormationHstCell) (z.B. "Durlach Turm")
└── Haltestelle 2 (FormationHstCell) (z.B. "Stupferich Ri")
└── ...
└── Haltestelle N_E (FormationHstCell) (Endhalte: FieldName += "_E")
FormationHstCell — Modus „Belegungsgrad“ (ShowBelegungsGrad = true)| Element | Property | Position | Darstellung |
|---|---|---|---|
| Fahrzeug-ID | FahrzeugId | Links | Text (z.B. „V661-1556“). Rot wenn FzgChanged = true |
| Belegung (%) | Belegung | Rechts oben | Zahl in Blau, fett, 10pt. Nur sichtbar wenn HasFzg = true |
FormationHstCell — Modus „Barrierefreiheit“ (ShowBelegungsGrad = false)| Element | Property | Position | Darstellung |
|---|---|---|---|
| Fahrzeug-ID | FahrzeugId | Links | Text. Rot wenn FzgChanged = true |
| Barrierefreiheit „B“ | Barrierefreiheit |
Rechts oben (10pt) |
B = barrierefrei (true)B = nicht barrierefrei ( false, fett)B = unbekannt ( null)Ausgeblendet wenn HasFzg = false
|
| Ankunft=Abfahrt „A“ | AnkunftGleichAbfahrt |
Rechts unten (10pt) |
A = Ankunft gleich Abfahrt (true)A = Ankunft ungleich Abfahrt ( false, fett)Ausgeblendet wenn HasFzg = false
|
| Element | Property | Darstellung |
|---|---|---|
| Zeilen-Alternierung | Alternated | Hintergrund #22C3B091 (leichtes Beige) bei jeder zweiten Datenabruf-Gruppe |
| Zeitstempel-Spalte | — | Hintergrund Khaki, fett (FormatCondition) |
| Fzg Position | FzgPosition | Integer (1-basiert). Gibt die Position des Fahrzeugs innerhalb der Formation an. |
Zeitstempel Fzg Pos Karlsruhe Haup Söllingen (b.K. Berghausen Am Grötzingen Kru ...
02:59:59:8600 1 V86084_4562 V86084_4562 [1] V86084_4562 [0] V86084_4562 [1] ...
03:04:29:4510 1 V86084_4562 V86084_4562 [1] V86084_4562 [0] V86084_4562 [1] ...
^ ^ ^
Belegung % Belegung % Belegung %
(blau, fett) (blau, fett) (blau, fett)
Zeitstempel Fzg Pos Durlach Turm Stupferich Ri Stupferich Ki ...
12:27:58:3250 1 V661-1556 [B,A] V661-1556 [B,A] V661-1556 [B,A] ...
^ ^
| Ankunft=Abfahrt (grün/rot)
Barrierefreiheit (grün/rot/blau)
ExpandoObject mit Zeitstempel, FzgPosition und dynamischen
Haltestellen-Keys (jeweils FormationHstCell) aufgebaut.
Bei der Endhalte eines Abschnitts wird "_E" an den FieldName angehängt, um Duplikate zu vermeiden.
Die FzgChanged-Erkennung vergleicht die FahrzeugId mit der vorherigen Haltestelle.
Quellen: FahrtModelFormation.cs | FahrtModelMitFahrzeug.cs | MainWindow.xaml (Zeilen 29–145, 733–860)
ImportInfoModel ← Betriebstag-Übersicht (JSON: _vdv454_import_*.json)
│
├── OutputFahrtModel ← Eine Fahrt mit allen Datenabrufen
│ ├── IstFahrtRowModel[] ← Einzelne Datenabruf-Zeilen (FahrtRows)
│ │ ├── IstHaltRowModel[] ← Haltestellen pro Abruf (IstHalts)
│ │ └── IstFormationXmlModel ← Formations-Daten (Fahrzeuge, Gruppen, Haltestellen)
│ └── OutputFzgModel[] ← Fahrzeug-Kopfdaten (FormationModels)
│
└── UI-Modelle (VBK_VDV454_Import_UI/Models/)
├── FahrtModel ← Flaches Modell für Fahrten-Grid
│ ├── HstColumn ← Dynamische Spalten-Definition
│ └── HstCell ← Zellen-Daten (Abfahrt, Prognose, Besetztgrad, ...)
└── FahrtModelFormation ← Formation-spezifisches Modell
├── FormationHstColumn ← Spalte mit Abschnitt-Zuordnung
└── FormationHstCell ← Zelle mit Fzg-ID, Belegung, Barrierefreiheit
Wert (IstAbfahrtPrognoseStatus) | Farbe | Bedeutung |
|---|---|---|
"prognose" | Blau | Berechnete Prognose |
"real" | Grün | Echtzeit-Messwert |
"geschaetzt" | Orange | Geschätzter Wert |
"unbekannt" | Rot | Status unbekannt |
Wert (Besetztgrad) | Farbe | Bedeutung |
|---|---|---|
"schwach besetzt" | Grün | Wenig Fahrgäste |
"normal besetzt" | Orange | Normale Auslastung |
"stark besetzt" | Rot | Hohe Auslastung |
"unbekannt" | Grau | Keine Daten |
| Buchstabe | Position | Farbe | Property | Bedeutung |
|---|---|---|---|---|
| E | Links oben | Rot | Einsteigeverbot | An dieser Haltestelle darf nicht eingestiegen werden |
| A | Links unten | Rot | Aussteigeverbot | An dieser Haltestelle darf nicht ausgestiegen werden |
| D | Links mitte | Rot | Durchfahrt | Haltestelle wird ohne Halt durchfahren |
| Spalte | Typ | Beschreibung |
|---|---|---|
| K. (Komplettfahrt) | bool (2-stufig) | Datensatz enthält vollständige Fahrt-Information |
| P. (Prognose fortlaufend) | bool (2-stufig) | Fortlaufender Status: bleibt aktiv bis Prognose nicht mehr möglich |
| P. (Prognose möglich) | bool? (3-stufig) | Aktueller Status des Datensatzes: true, false oder unbestimmt (null) |
| Element | Bedingung / Modus | Darstellung |
|---|---|---|
| Fahrzeug-ID Text | FzgChanged = true | Rot (Fahrzeug hat Position gewechselt) |
Modus: Belegungsgrad (ShowBelegungsGrad = true) | ||
| Belegung (%) | Zahl rechts oben in Zelle | Blau, fett, 10pt (z.B. 0, 1, 2, 4) |
Modus: Barrierefreiheit (ShowBelegungsGrad = false) | ||
| Barrierefreiheit „B“ | Barrierefreiheit = true | Grün (rechts oben) |
| Barrierefreiheit „B“ | Barrierefreiheit = false | Rot, fett (rechts oben) |
| Barrierefreiheit „B“ | Barrierefreiheit = null | Blau (rechts oben) |
| Ankunft=Abfahrt „A“ | AnkunftGleichAbfahrt = true | Grün (rechts unten) |
| Ankunft=Abfahrt „A“ | AnkunftGleichAbfahrt = false | Rot, fett (rechts unten) |
| Beide Modi | ||
| Zeilen-Hintergrund | Alternated = true | Leichtes Beige (#22C3B091) |
| Element | Darstellung |
|---|---|
| Fokussierte Zeile (Master-Grids) | Fett + Hintergrund #eeeeee |
| Fokussierte Zeile (Detail-Grids) | Hintergrund #eeeeee (ohne Fett) |
| Zeitstempel-Spalte | Hintergrund Khaki + Fett |