This commit is contained in:
Kilian Wirl 2026-04-15 11:34:46 +02:00
parent cb1ecafc8a
commit a0ff54d0b3
3 changed files with 333 additions and 201 deletions

View File

@ -262,128 +262,164 @@ namespace Deckungsbeitrag
#endregion
#region ObjectListView-Events
private void Load_OLV(ObjectListView olv, List<View_Auftrag_Expedit> auftragliste)
{
// ========== LAYOUT UND UPDATE PAUSIEREN ==========
olv.BeginUpdate(); // Stoppt Datenaktualisierungen/Redraws
olv.SuspendLayout(); // Stoppt Layout-Berechnungen (Anchor/Dock)
this.UseWaitCursor = true;
// ========== SPALTEN AUTOMATISCH AUS MODEL ERTELLEN ==========
Generator.GenerateColumns(olv, typeof(View_Auftrag_Expedit), true);
// === LAYOUT & UPDATE PAUSIEREN ===
olv.BeginUpdate();
olv.SuspendLayout();
// ========== SPALTEN ANPASSEN ==========
var aufgabeCol = olv.AllColumns.Cast<OLVColumn>().FirstOrDefault(col => col.Text == "Aufgabe");
try
{
// === SPALTEN NUR EINMAL GENERIEREN (falls sinnvoll) ===
if (olv.AllColumns.Count == 0)
{
Generator.GenerateColumns(olv, typeof(View_Auftrag_Expedit), true);
ConfigureColumns(olv);
}
// === IMAGE-LIST (einmalig zentral konfigurieren, hier nur zuweisen) ===
Program.imagelist.ImageSize = new Size(24, 24);
olv.SmallImageList = Program.imagelist;
// === TOOLTIP-EVENT EINMALIG REGISTRIEREN ===
olv.CellToolTipShowing -= Olv_CellToolTipShowing;
olv.CellToolTipShowing += Olv_CellToolTipShowing;
// === DATEN LADEN ===
OLV_SetObjects(olv, auftragliste);
// === SORTIERUNG ===
var statusCol = olv.AllColumns.Cast<OLVColumn>().FirstOrDefault(c => c.Text == "Status");
var liefertagCol = olv.AllColumns.Cast<OLVColumn>().FirstOrDefault(c => c.Text == "Liefertag");
if (statusCol != null) olv.PrimarySortColumn = statusCol;
if (liefertagCol != null) olv.SecondarySortColumn = liefertagCol;
if (olv.Name.Contains("Rampe") && liefertagCol != null)
olv.Sort(liefertagCol);
else
olv.Sort();
// === SPALTEN JE NACH TAB/ROLLE ===
GetUnvisibleColumns(olv);
// === SPALTENBREITE ANPASSEN ===
olv = Funktionen.Columns_Resize(null, olv).olv;
// === FILTER ===
olv.FilterMenuBuildStrategy = new MeinFilterMenu();
}
finally
{
olv.ResumeLayout();
olv.EndUpdate();
olv.Focus();
this.UseWaitCursor = false;
}
}
private void ConfigureColumns(ObjectListView olv)
{
var columns = olv.AllColumns.Cast<OLVColumn>().ToList();
OLVColumn Find(string header) =>
columns.FirstOrDefault(c => String.Equals(c.Text, header, StringComparison.OrdinalIgnoreCase));
// --- Aufgabe-Icon ---
var aufgabeCol = Find("Aufgabe");
if (aufgabeCol != null)
{
aufgabeCol.ImageGetter = rowObject =>
{
var auftrag = rowObject as View_Auftrag_Expedit;
return string.IsNullOrEmpty(auftrag?.AufgabeBezeichnung) ? -1 : 0;
var a = rowObject as View_Auftrag_Expedit;
if (a == null) return -1;
return string.IsNullOrEmpty(a.AufgabeBezeichnung) ? -1 : 0;
};
}
var kundeCol = olv.AllColumns.Cast<OLVColumn>().FirstOrDefault(col => col.Text == "Kunde");
if (kundeCol != null)
// --- Kunde-Icon ---
var kundeCol = Find("Kunde");
if (kundeCol != null)
{
kundeCol.ImageGetter = rowObject =>
{
var auftrag = rowObject as View_Auftrag_Expedit;
return string.IsNullOrEmpty(auftrag?.Zusatz) ? -1 : 1;
var a = rowObject as View_Auftrag_Expedit;
if (a == null) return -1;
return string.IsNullOrEmpty(a.Zusatz) ? -1 : 1;
};
}
var dirtCol = olv.AllColumns.Cast<OLVColumn>().FirstOrDefault(col => col.Text == "Schmutzig");
// --- Schmutzig / Sauber ---
var dirtCol = Find("Schmutzig");
if (dirtCol != null)
{
dirtCol.HeaderImageKey = "dirt";
dirtCol.ShowTextInHeader = false;
dirtCol.MinimumWidth = dirtCol.MaximumWidth = 80;
}
var cleanCol = olv.AllColumns.Cast<OLVColumn>().FirstOrDefault(col => col.Text == "Sauber");
var cleanCol = Find("Sauber");
if (cleanCol != null)
{
cleanCol.HeaderImageKey = "clean";
cleanCol.ShowTextInHeader = false;
cleanCol.MinimumWidth = dirtCol.MaximumWidth = 80;
cleanCol.MinimumWidth = cleanCol.MaximumWidth = 80; // Bugfix: nicht dirtCol.MaximumWidth
}
var primaryCol = olv.AllColumns.Cast<OLVColumn>().FirstOrDefault(col => col.Text == "Status");
if (primaryCol != null) olv.PrimarySortColumn = primaryCol;
var secondaryCol = olv.AllColumns.Cast<OLVColumn>().FirstOrDefault(col => col.Text == "Liefertag");
if (secondaryCol != null) olv.SecondarySortColumn = secondaryCol;
var druckenCol = olv.AllColumns.Cast<OLVColumn>().FirstOrDefault(col => col.Text == "Etikett");
// --- Etikett-Button ---
var druckenCol = Find("Etikett");
if (druckenCol != null)
{
druckenCol.IsButton = true; // Als Button rendern
druckenCol.ButtonSizing = OLVColumn.ButtonSizingMode.CellBounds; // Button füllt gesamte Zelle
druckenCol.IsButton = true;
druckenCol.ButtonSizing = OLVColumn.ButtonSizingMode.CellBounds;
druckenCol.HeaderImageKey = "print";
druckenCol.ShowTextInHeader = false;
druckenCol.MinimumWidth = druckenCol.MaximumWidth = 80;
}
var fertigCol = olv.AllColumns.Cast<OLVColumn>().FirstOrDefault(col => col.Text == "Abschließen");
// --- Abschließen-Button ---
var fertigCol = Find("Abschließen");
if (fertigCol != null)
{
fertigCol.IsButton = true; // Als Button rendern
fertigCol.ButtonSizing = OLVColumn.ButtonSizingMode.CellBounds; // Button füllt gesamte Zelle
fertigCol.IsButton = true;
fertigCol.ButtonSizing = OLVColumn.ButtonSizingMode.CellBounds;
fertigCol.HeaderImageKey = "abschließen";
fertigCol.ShowTextInHeader = false;
fertigCol.MinimumWidth = fertigCol.MaximumWidth = 80;
}
}
private void Olv_CellToolTipShowing(object sender, ToolTipShowingEventArgs e)
{
// Kein Model, kein Tooltip
if (e.Model == null || e.Column == null)
return;
// ========== SPALTEN JE NACH TAB UND ROLLE AUSBLENDEN ==========
GetUnvisibleColumns(olv);
//if (_settings.OLV_State != null) olv.RestoreState(_settings.OLV_State);
// ========== IMAGE-LIST ZUWEISEN ==========
// SmallImageList für Icons in Detail-View (24x24 Pixel standard)
Program.imagelist.ImageSize = new Size(24, 24);
olv.SmallImageList = Program.imagelist; // Voraussetzung: imagelist mit Icon Index 0 gefüllt
// ========== TOOLTIP FÜR ICON-SPALTEN ==========
// Automatischer Cell-Tooltip bei Mouse-Hover
olv.CellToolTipShowing += (s, e) =>
// Aufgabe-Tooltip
if (e.Column.Text == "Aufgabe" && e.Model is View_Auftrag_Expedit expeditAufgabe)
{
// Nur für Icon-Spalte (Index 10) und gültiges Model
if (e.Column.Text == "Aufgabe" && e.Model is View_Auftrag_Expedit expedit)
{
Auftrag auftrag = Auftrag.GetAuftrag(expedit.AuftragID);
// Lade Bezeichnung der Aufgabe als Tooltip-Text
e.Text = Aufgabe.GetAufgabe(null, auftrag.AufgabeID).Bezeichnung;
}
// Nur für Icon-Spalte (Index 1) und gültiges Model
if (e.Column.Text == "Kunde" && e.Model is View_Auftrag_Expedit expedit1)
{
Auftrag _auftrag = Auftrag.GetAuftrag(expedit1.AuftragID);
if (!string.IsNullOrWhiteSpace(Kunde.GetKunde(null, _auftrag.KundeID, null).Anmerkung))
{
// Lade Anmerkung als Tooltip-Text
e.Text = Kunde.GetKunde(null, _auftrag.KundeID, null).Anmerkung;
}
}
if (e.Column.Text == "Fahrer" && e.Model is Auftrag auftrag1)
{
e.Text = auftrag1.ZusatzInfo;
}
};
var auftrag = Auftrag.GetAuftrag(expeditAufgabe.AuftragID);
var aufgabe = Aufgabe.GetAufgabe(null, auftrag.AufgabeID);
e.Text = aufgabe?.Bezeichnung;
return;
}
// ========== DATEN LADEN ==========
// WICHTIG: SetObjects NACH Column-Konfiguration aufrufen!
OLV_SetObjects(olv, auftragliste);
// ========== SORTIERUNG NACH SPALTEN ==========
if (olv.Name.Contains("Rampe")) olv.Sort(secondaryCol);
else olv.Sort();
// ========== SPALTENBREITE ANPASSEN ==========
olv = Funktionen.Columns_Resize(null, olv).olv;
// ========== FILTER AKTIVIEREN UND ZUWEISEN ==========
olv.FilterMenuBuildStrategy = new MeinFilterMenu();
// ========== AUFRÄUMEN & AKTIVIEREN ==========
olv.ResumeLayout(); // Layout-Pause beenden, Positionen neu berechnen
olv.EndUpdate(); // Update-Pause beenden, Daten neu zeichnen
olv.Focus(); // OLV fokussieren (Tastaturbedienung aktivieren)
this.UseWaitCursor = false;
// Kunde-Tooltip
if (e.Column.Text == "Kunde" && e.Model is View_Auftrag_Expedit expeditKunde)
{
var auftrag = Auftrag.GetAuftrag(expeditKunde.AuftragID);
var kunde = Kunde.GetKunde(null, auftrag.KundeID, null);
if (!string.IsNullOrWhiteSpace(kunde?.Anmerkung))
e.Text = kunde.Anmerkung;
return;
}
// Fahrer-Tooltip Typfix: hier passt View_Auftrag_Expedit besser
if (e.Column.Text == "Fahrer" && e.Model is View_Auftrag_Expedit expeditFahrer)
{
e.Text = expeditFahrer.Zusatz;
}
}
private void ObjectListViewAuftrag_FormatCell(object sender, FormatCellEventArgs e)
{
@ -538,131 +574,232 @@ namespace Deckungsbeitrag
break;
}
}
private void ObjectListViewAuftrag_ButtonClick(object sender, BrightIdeasSoftware.CellClickEventArgs e)
{
ObjectListView olv = (ObjectListView)sender;
Auftrag _auftrag = Auftrag.GetAuftrag(((View_Auftrag_Expedit)e.Model).AuftragID);
if (e.Column.Text == "Abschließen")
private void ObjectListViewAuftrag_ButtonClick(object sender, CellClickEventArgs e)
{
var olv = (ObjectListView)sender;
var view = (View_Auftrag_Expedit)e.Model;
var auftrag = Auftrag.GetAuftrag(view.AuftragID);
this.UseWaitCursor = true;
try
{
// Wenn BenutzerRolle Frottee dann Abteilung Frottee Beendet.
if (this.benutzer.Rolle == BenutzerRolle.Frottee) { Auftrag_Fertig(); Neuladen_OLV(olv); return; }
if (olv.CheckedItems.Count > 0)
switch (e.Column.Text)
{
if (MessageBox.Show($"Möchtest du die ausgewählten {olv.CheckedItems.Count} Aufträge abschließen?", "AUFTRÄGE FERTIG", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) return;
else
{
foreach (OLVListItem item in olv.CheckedItems)
{
this.auftrag = (Auftrag)item.RowObject;
Auftrag_Fertig();
}
var column = olv.AllColumns.Cast<OLVColumn>().FirstOrDefault(col => col.Text == "Kunde");
if (column != null && column.HeaderCheckBox) olv.UncheckHeaderCheckBox(column);
}
}
else
{
if (this.auftrag != _auftrag) altecontclean = null;
case "Abschließen":
HandleAbschliessenClick(olv, auftrag);
break;
this.auftrag = _auftrag;
if (this.auftrag.ContainerClean == 0)
{
if (meldung.NoCleanContainer() == DialogResult.OK) return;
}
else
{
if (altecontclean != null && this.auftrag.ContainerClean != altecontclean)
{
switch (meldung.DifferentCleanContainer())
{
case DialogResult.Cancel:
return;
case DialogResult.Yes:
{
this.auftrag.Gedruckt = DateTime.Now;
this.auftrag.GedrucktVon = benutzer.BenutzerID;
bool nocont = false;
if (this.auftrag.ContainerClean > 10)
{
if (MessageBox.Show("Möchtest du die Containeranzahl am Etikett anzeigen?", "FRAGE", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
{
nocont = true;
}
else nocont = false;
}
try
{
Funktionen.Etikett_Drucken(auftrag, nocont);
}
catch (Exception ex)
{
MessageBox.Show("Etiketten konnten nicht gedruckt werden. Versuche es nochmals.", "DRUCKFEHLER", MessageBoxButtons.OK, MessageBoxIcon.Error);
Program.AddFehler(this.benutzer, ex.Message, ex.StackTrace, null);
return;
}
}
break;
case DialogResult.No:
this.auftrag.Erstellt = DateTime.Now;
this.auftrag.ErstelltVon = (int)benutzer.BenutzerID;
break;
default:
break;
}
}
Auftrag_Fertig();
}
case "Etikett":
HandleEtikettClick(auftrag);
break;
}
}
if (e.Column.Text == "Etikett")
finally
{
this.auftrag = _auftrag;
if (this.auftrag.AufgabeID != null)
{
if (meldung.GetAchtung(this, $"Bei dem ausgewählten Auftrag ist die Aufgabe {Aufgabe.GetAufgabe(null, auftrag.AufgabeID).Bezeichnung} zu erledigen. Hast du die Aufgabe erledigt? ", false) == DialogResult.No) return;
}
if (this.auftrag.ContainerClean != 0)
{
letzterLiefertag = this.auftrag.Liefertag;
}
else
{
string eingabe = PromptForText(
"Der Auftrag hat keine sauberen Container oder Pakete. \n\n" +
"Bitte gib an wieviele Container oder Pakete der Auftrag hat:",
"Container/Pakete eingeben",
"0");
if (string.IsNullOrWhiteSpace(eingabe) || !int.TryParse(eingabe, out int anzahl))
{
this.UseWaitCursor = false;
return;
}
this.auftrag.ContainerClean = anzahl;
}
//ETIKETT DRUCKEN
DialogResult result = Funktionen.Etikett_Drucken(auftrag, nocont);
if (result == DialogResult.OK)
{
this.auftrag.Gedruckt = DateTime.Now;
this.auftrag.GedrucktVon = (int)this.benutzer.BenutzerID;
this.auftrag.Status = AuftragStatus.Vorbereitet;
this.auftrag.Save();
this.auftrag = null;
}
Neuladen_OLV(olv);
this.UseWaitCursor = false;
}
}
/// <summary>
/// Behandelt den Fall, dass der Button in der Spalte Abschliessen geclickt wurde
/// </summary>
/// <param name="olv"></param>
/// <param name="auftrag"></param>
private void HandleAbschliessenClick(ObjectListView olv, Auftrag auftrag)
{
// Sonderfall Frottee: nur Abteilung beenden und raus
if (this.benutzer.Rolle == BenutzerRolle.Frottee)
{
this.auftrag = auftrag;
Auftrag_Fertig();
return;
}
Neuladen_OLV(olv);
this.UseWaitCursor = false;
if (olv.CheckedItems.Count > 0)
{
HandleBatchAbschliessen(olv);
return;
}
HandleSingleAbschliessen(auftrag);
}
/// <summary>
/// Wenn angehackte Datensätze im Bulk abeschlossen werden sollen.
/// Hier sind mehrere oder nur ein Auftrag abschließen möglich.
/// </summary>
/// <param name="olv"></param>
private void HandleBatchAbschliessen(ObjectListView olv)
{
var count = olv.CheckedItems.Count;
var result = MessageBox.Show(
$"Möchtest du die ausgewählten {count} Aufträge abschließen?",
"AUFTRÄGE FERTIG",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (result == DialogResult.No)
return;
foreach (OLVListItem item in olv.CheckedItems)
{
this.auftrag = (Auftrag)item.RowObject;
Auftrag_Fertig();
}
var kundeColumn = olv.AllColumns
.Cast<OLVColumn>()
.FirstOrDefault(col => col.Text == "Kunde");
if (kundeColumn != null && kundeColumn.HeaderCheckBox)
olv.UncheckHeaderCheckBox(kundeColumn);
}
/// <summary>
/// Wenn der Button geclickt wurde ohne anhacken. Es wird garantiert nur 1 Auftrag abgeschlossen
/// </summary>
/// <param name="auftrag"></param>
private void HandleSingleAbschliessen(Auftrag auftrag)
{
if (this.auftrag != auftrag)
altecontclean = null;
this.auftrag = auftrag;
if (this.auftrag.ContainerClean == 0)
{
if (meldung.NoCleanContainer() == DialogResult.OK)
return;
}
else
{
if (!HandleContainerCleanChange())
return;
}
Auftrag_Fertig();
}
/// <summary>
/// Behandelt den Fall, dass sich ContainerClean geändert hat.
/// Gibt false zurück, wenn der Vorgang abgebrochen werden soll.
/// </summary>
private bool HandleContainerCleanChange()
{
if (altecontclean == null || this.auftrag.ContainerClean == altecontclean)
return true;
switch (meldung.DifferentCleanContainer())
{
case DialogResult.Cancel:
return false;
case DialogResult.Yes:
return TryDruckMitNeuemContainerClean();
case DialogResult.No:
this.auftrag.Erstellt = DateTime.Now;
this.auftrag.ErstelltVon = (int)benutzer.BenutzerID;
return true;
default:
return true;
}
}
/// <summary>
/// Wenn eine neue Anzahl an sauberen Containern eingegeben wurde wird ein erneuter Druck abgefragt.
/// </summary>
private bool TryDruckMitNeuemContainerClean()
{
this.auftrag.Gedruckt = DateTime.Now;
this.auftrag.GedrucktVon = benutzer.BenutzerID;
var nocont = false;
if (this.auftrag.ContainerClean > 10)
{
var res = MessageBox.Show(
"Möchtest du die Containeranzahl am Etikett anzeigen?",
"FRAGE",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
nocont = (res == DialogResult.No);
}
try
{
Funktionen.Etikett_Drucken(auftrag, nocont);
return true;
}
catch (Exception ex)
{
MessageBox.Show(
"Etiketten konnten nicht gedruckt werden. Versuche es nochmals.",
"DRUCKFEHLER",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
Program.AddFehler(this.benutzer, ex.Message, ex.StackTrace, null);
return false;
}
}
/// <summary>
/// Behandelt den Fall, dass der Button in der Spalte Etikett geclickt wurde.
/// </summary>
/// <param name="auftrag"></param>
private void HandleEtikettClick(Auftrag auftrag)
{
this.auftrag = auftrag;
if (this.auftrag.AufgabeID != null)
{
var aufgabe = Aufgabe.GetAufgabe(null, auftrag.AufgabeID);
var text = $"Bei dem ausgewählten Auftrag ist die Aufgabe {aufgabe.Bezeichnung} zu erledigen. Hast du die Aufgabe erledigt? ";
if (meldung.GetAchtung(this, text, false) == DialogResult.No)
return;
}
PrepareContainerCleanForEtikett();
var result = Funktionen.Etikett_Drucken(auftrag, nocont);
if (result == DialogResult.OK)
{
this.auftrag.Gedruckt = DateTime.Now;
this.auftrag.GedrucktVon = (int)this.benutzer.BenutzerID;
this.auftrag.Status = AuftragStatus.Vorbereitet;
this.auftrag.Save();
this.auftrag = null;
}
}
private void PrepareContainerCleanForEtikett()
{
if (this.auftrag.ContainerClean != 0)
{
letzterLiefertag = this.auftrag.Liefertag;
return;
}
string eingabe = PromptForText(
"Der Auftrag hat keine sauberen Container oder Pakete. \n\n" +
"Bitte gib an wieviele Container oder Pakete der Auftrag hat:",
"Container/Pakete eingeben",
"0");
if (string.IsNullOrWhiteSpace(eingabe) || !int.TryParse(eingabe, out int anzahl))
{
this.UseWaitCursor = false;
return;
}
this.auftrag.ContainerClean = anzahl;
}
/// <summary>
/// Die Objecte der ObjectListView werden neu geladen.
/// </summary>

View File

@ -273,11 +273,6 @@ namespace Deckungsbeitrag
}
private void ButtonProgramm_Click(object sender, EventArgs e)
{
FormProgrammauswahl auswahl = new FormProgrammauswahl();
if (auswahl.ShowDialog() == DialogResult.OK)
{
DatenLesen();
}
}
private void ButtonAufgEnt_Click(object sender, EventArgs e)
{

View File

@ -95,5 +95,5 @@ Build-Info:
- 🔄 Wenn Frottee-Expedit auch Relamation bearbeitet, muss BenutzerRolle abgefragt werden. siehe CHANGES. [FormFehlmengeCount.cs]
- 🔄 Zuweisung zu Fahrer muss geklärt werden. [Funktionen.cs]
Installation: 15.04.2026 10:13
Installation: 15.04.2026 11:03
=====================================