using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using Elwig.Helpers; using Elwig.Helpers.Billing; using Elwig.Models.Entities; using ScottPlot.Plottables; using ScottPlot; namespace Elwig.Windows { public partial class ChartWindow : ContextWindow { public static readonly Color ColorUngebunden = Colors.Blue; public static readonly Color ColorGebunden = Colors.Gold; public readonly int Year; public readonly int AvNr; public Season Season; public string CurrencySymbol; private PaymentVar PaymentVar; private bool HasChanged = false; private bool Updating = false; private Scatter DataPlot; private Scatter? GebundenPlot; private Marker HighlightedPointPlot; private Marker PrimaryMarkedPointPlot; private Marker SecondaryMarkedPointPlot; private Text TooltipPlot; private static readonly LegendItem UngebundenLegend = new() { LabelText = "Ungebunden", LineWidth = 1, LineColor = ColorUngebunden, MarkerStyle = new(MarkerShape.FilledCircle, 5, ColorUngebunden) }, GebundenLegend = new() { LabelText = "Gebunden", LineWidth = 1, LineColor = ColorGebunden, MarkerStyle = new(MarkerShape.FilledCircle, 5, ColorGebunden) }, LdwLegend = new() { LabelText = "68 °Oe (LDW)", LineWidth = 2, LineColor = Colors.Red, MarkerStyle = MarkerStyle.None }, QuwLegend = new() { LabelText = "73 °Oe (QUW)", LineWidth = 2, LineColor = Colors.Orange, MarkerStyle = MarkerStyle.None }, KabLegend = new() { LabelText = "84 °Oe (KAB)", LineWidth = 2, LineColor = Colors.Green, MarkerStyle = MarkerStyle.None }; private (Graph? Graph, int Index) LastHighlighted = (null, -1); private (Graph? Graph, int Index) Highlighted = (null, -1); private Graph? ActiveGraph = null; private int PrimaryMarkedPoint = -1; private int SecondaryMarkedPoint = -1; private bool HoverChanged = false; private bool HoverActive = false; private bool FillingInputs = false; private List GraphEntries = []; private GraphEntry? SelectedGraphEntry => (GraphEntry)GraphList.SelectedItem; private List Vaributes = []; private bool AllVaributesAssigned => Vaributes.All(v => v.AssignedGraphId != null); private bool AllVaributesAssignedAbgew => Vaributes.All(v => v.AssignedAbgewGraphId != null); public ChartWindow(int year, int avnr) { InitializeComponent(); Year = year; AvNr = avnr; using var ctx = new AppDbContext(); Season = ctx.Seasons.Find(year) ?? throw new ArgumentException("Season not found"); CurrencySymbol = Season.Currency.Symbol ?? Season.Currency.Code; PriceInput.Unit = $"{CurrencySymbol}/kg"; GebundenFlatBonus.Unit = $"{CurrencySymbol}/kg"; PaymentVar = ctx.PaymentVariants.Find(year, avnr) ?? throw new ArgumentException("PaymentVar not found"); Title = $"{PaymentVar?.Name} - Lese {year} - Elwig"; LockContext = true; } private void Window_Loaded(object sender, RoutedEventArgs evt) { } private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { if (HasChanged) { var r = MessageBox.Show("Soll das Fenster wirklich geschlossen werden? Nicht gespeicherte Änderungen werden NICHT übernommen!", "Schließen bestätigen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No); if (r != MessageBoxResult.Yes) { e.Cancel = true; return; } } } private void SetHasChanged(bool hasChanged = true) { HasChanged = hasChanged; SaveButton.IsEnabled = hasChanged; } private async Task RefreshGraphList(AppDbContext ctx) { PaymentVar = await ctx.PaymentVariants.FindAsync(Year, AvNr) ?? throw new ArgumentException("PaymentVar not found"); Season = await ctx.Seasons.FindAsync(Year) ?? throw new ArgumentException("Season not found"); CurrencySymbol = Season.Currency.Symbol ?? Season.Currency.Code; PriceInput.Unit = $"{CurrencySymbol}/kg"; GebundenFlatBonus.Unit = $"{CurrencySymbol}/kg"; try { var data = EditBillingData.FromJson(PaymentVar.Data, Utils.GetVaributes(ctx, Year)); var paymentEntries = data.GetPaymentGraphEntries(ctx, Season); GraphEntries = [ ..paymentEntries, ..data.GetQualityGraphEntries(ctx, Season, paymentEntries.Any() ? paymentEntries.Max(e => e.Id) : 0) ]; } catch (KeyNotFoundException ex) { var key = ex.Message.Split('\'')[1].Split('\'')[0]; MessageBox.Show($"Fehler beim Laden der Auszahlungsvariante:\n\n" + $"Mit unbekanntem Attribut '{key}' kann nicht umgegangen werden.", "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); } catch (ArgumentException) { MessageBox.Show($"Fehler beim Laden der Auszahlungsvariante:\n\n" + $"Die Daten der Auszahlungsvariante entsprechen nicht dem benötigtem Format.", "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); } catch (Exception ex) { MessageBox.Show("Fehler beim Laden der Auszahlungsvariante:\n\n" + ex.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); } Vaributes = Utils.GetVaributeList(ctx, Year); GraphEntries.ForEach(e => { e.Vaributes.ForEach(v => { var found = Vaributes.Find(a => a.Variety?.SortId == v.Variety?.SortId && a.Attribute?.AttrId == v.Attribute?.AttrId && a.Cultivation?.CultId == v.Cultivation?.CultId); if (found == null) return; if (e.Abgewertet) { found.AssignedAbgewGraphId = e.Id; } else { found.AssignedGraphId = e.Id; } }); }); FillingInputs = true; ControlUtils.RenewItemsSource(VaributeInput, Vaributes); FillingInputs = false; ControlUtils.RenewItemsSource(GraphList, GraphEntries, GraphList_SelectionChanged, ControlUtils.RenewSourceDefault.First); RefreshInputs(); } private void RefreshInputs() { ResetPlot(); if (SelectedGraphEntry != null) { CopyButton.IsEnabled = true; DeleteButton.IsEnabled = true; EnableTextBox(OechsleInput); GebInput.IsEnabled = SelectedGraphEntry?.GebundenGraph != null; GebundenTypeFixed.IsEnabled = true; GebundenTypeGraph.IsEnabled = true; GebundenTypeNone.IsEnabled = true; VaributeInput.IsEnabled = true; AbgewertetInput.IsEnabled = true; EnableOptionButtons(); FillInputs(); } else { CopyButton.IsEnabled = false; DeleteButton.IsEnabled = false; DisableTextBox(OechsleInput); GebInput.IsEnabled = false; DisableOptionButtons(); } if (!PaymentVar.TestVariant) { AddButton.IsEnabled = false; CopyButton.IsEnabled = false; DeleteButton.IsEnabled = false; DisableTextBox(PriceInput); GebundenTypeFixed.IsEnabled = false; GebundenTypeGraph.IsEnabled = false; GebundenTypeNone.IsEnabled = false; VaributeInput.IsEnabled = false; AbgewertetInput.IsEnabled = false; } GC.Collect(); } private void FillInputs() { FillingInputs = true; AbgewertetInput.IsChecked = SelectedGraphEntry?.Abgewertet; if (SelectedGraphEntry?.GebundenFlatBonus is double bonus) { GebundenTypeFixed.IsChecked = true; GebundenFlatBonus.Text = $"{bonus}"; } else if (SelectedGraphEntry?.GebundenGraph != null) { GebundenTypeGraph.IsChecked = true; GebundenFlatBonus.Text = ""; } else { GebundenTypeNone.IsChecked = true; GebundenFlatBonus.Text = ""; } ControlUtils.SelectItems(VaributeInput, SelectedGraphEntry?.Vaributes ?? []); InitPlot(); ChangeActiveGraph(SelectedGraphEntry?.DataGraph); OechsleInput.Text = "73"; OechslePricePlot.IsEnabled = true; FillingInputs = false; } protected override async Task OnRenewContext(AppDbContext ctx) { await RefreshGraphList(ctx); } private void InitPlot() { RefreshGradationLines(); if (SelectedGraphEntry?.GebundenGraph != null) { GebundenPlot = OechslePricePlot.Plot.Add.Scatter(SelectedGraphEntry.GebundenGraph.DataX, SelectedGraphEntry.GebundenGraph.DataY); GebundenPlot.LineStyle.Color = ColorGebunden; GebundenPlot.Color = ColorGebunden; GebundenPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorGebunden); } DataPlot = OechslePricePlot.Plot.Add.Scatter(SelectedGraphEntry!.DataGraph.DataX, SelectedGraphEntry!.DataGraph.DataY); DataPlot.LineStyle.Color = ColorUngebunden; DataPlot.Color = ColorUngebunden; DataPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorUngebunden); OechslePricePlot.Plot.Axes.SetLimits(Math.Min(GraphEntry.MinX, GraphEntry.MinXGeb) - 1, GraphEntry.MaxX + 1, -0.1, 1.5); HighlightedPointPlot = OechslePricePlot.Plot.Add.Marker(0, 0, MarkerShape.OpenCircle, 10, Colors.Red); HighlightedPointPlot.IsVisible = false; PrimaryMarkedPointPlot = OechslePricePlot.Plot.Add.Marker(0, 0, MarkerShape.FilledCircle, 6, Colors.Red); PrimaryMarkedPointPlot.IsVisible = false; SecondaryMarkedPointPlot = OechslePricePlot.Plot.Add.Marker(0, 0, MarkerShape.FilledCircle, 6, Colors.Red); SecondaryMarkedPointPlot.IsVisible = false; OechslePricePlot.Refresh(); RefreshFreeZoom(); OechslePricePlot.Refresh(); } private void ResetPlot() { PrimaryMarkedPoint = -1; SecondaryMarkedPoint = -1; ChangeActiveGraph(null); HideGradationLines(); OechslePricePlot.Plot.Remove(DataPlot); if (GebundenPlot != null) { OechslePricePlot.Plot.Remove(GebundenPlot); GebundenPlot = null; } OechslePricePlot.Plot.Clear(); OechslePricePlot.Reset(); OechslePricePlot.Refresh(); } private void ChangeMarker(Marker point, bool visible, double x = 0, double y = 0) { point.Location = new Coordinates(x, y); point.IsVisible = visible; } private void EnableActionButtons() { if (PaymentVar.TestVariant) { LeftFlatButton.IsEnabled = true; RightFlatButton.IsEnabled = true; LinearIncreaseButton.IsEnabled = true; } } private void DisableActionButtons() { LeftFlatButton.IsEnabled = false; RightFlatButton.IsEnabled = false; InterpolateButton.IsEnabled = false; LinearIncreaseButton.IsEnabled = false; } private void FreeZoomInput_Changed(object sender, RoutedEventArgs evt) { RefreshFreeZoom(); } private void RefreshFreeZoom() { if (FreeZoomInput.IsChecked == true) { UnlockZoom(); } else { LockZoom(); } OechslePricePlot.Refresh(); } private void LockZoom() { ScottPlot.AxisRules.MaximumBoundary BoundaryRule = new( xAxis: OechslePricePlot.Plot.Axes.Bottom, yAxis: OechslePricePlot.Plot.Axes.Left, limits: new AxisLimits(GraphEntry.MinX - 1, GraphEntry.MaxX + 1, -0.1, 2)); ScottPlot.AxisRules.MaximumSpan SpanRule = new( xAxis: OechslePricePlot.Plot.Axes.Bottom, yAxis: OechslePricePlot.Plot.Axes.Left, xSpan: GraphEntry.MaxX - GraphEntry.MinX + 2, ySpan: 2.1); OechslePricePlot.Plot.Axes.Rules.Clear(); OechslePricePlot.Plot.Axes.Rules.Add(BoundaryRule); OechslePricePlot.Plot.Axes.Rules.Add(SpanRule); OechslePricePlot.Plot.Axes.SetLimits(GraphEntry.MinX - 1, GraphEntry.MaxX + 1, -0.1, 1.5); } private void UnlockZoom() { ScottPlot.AxisRules.MaximumSpan SpanRule = new( xAxis: OechslePricePlot.Plot.Axes.Bottom, yAxis: OechslePricePlot.Plot.Axes.Left, xSpan: (GraphEntry.MaxX - GraphEntry.MinX) * 1.5, ySpan: 3.5); OechslePricePlot.Plot.Axes.Rules.Clear(); OechslePricePlot.Plot.Axes.Rules.Add(SpanRule); } private void EnableOptionButtons() { FreeZoomInput.IsEnabled = true; GradationLinesInput.IsEnabled = true; TooltipInput.IsEnabled = true; } private void DisableOptionButtons() { FreeZoomInput.IsEnabled = false; GradationLinesInput.IsEnabled = false; TooltipInput.IsEnabled = false; } private void GradationLinesInput_Changed(object sender, RoutedEventArgs evt) { RefreshGradationLines(); } private void RefreshGradationLines() { if (GradationLinesInput.IsChecked == true && SelectedGraphEntry != null && !OechslePricePlot.Plot.PlottableList.OfType().Any()) { ShowGradationLines(); ShowLegend(); } else if (GradationLinesInput.IsChecked == false) { HideGradationLines(); HideLegend(); } OechslePricePlot.Refresh(); } private void ShowGradationLines() { OechslePricePlot.Plot.Add.VerticalLine(68, 2, Colors.Red); OechslePricePlot.Plot.Add.VerticalLine(73, 2, Colors.Orange); OechslePricePlot.Plot.Add.VerticalLine(84, 2, Colors.Green); } private void HideGradationLines() { OechslePricePlot.Plot.PlottableList.RemoveAll(p => p is VerticalLine); } private void ShowLegend() { OechslePricePlot.Plot.Legend.Alignment = Alignment.UpperLeft; OechslePricePlot.Plot.Legend.IsVisible = true; OechslePricePlot.Plot.Legend.ManualItems.Add(LdwLegend); OechslePricePlot.Plot.Legend.ManualItems.Add(QuwLegend); OechslePricePlot.Plot.Legend.ManualItems.Add(KabLegend); OechslePricePlot.Plot.Legend.ManualItems.Add(UngebundenLegend); if (SelectedGraphEntry?.GebundenGraph != null) OechslePricePlot.Plot.Legend.ManualItems.Add(GebundenLegend); } private void HideLegend() { OechslePricePlot.Plot.Legend.IsVisible = false; OechslePricePlot.Plot.Legend.ManualItems.Clear(); } private void UpdateSelectedPoint() { if (ActiveGraph == null || SelectedGraphEntry == null) return; SecondaryMarkedPoint = -1; ChangeMarker(SecondaryMarkedPointPlot, false); if (int.TryParse(OechsleInput.Text, out int oe)) { if (oe >= ActiveGraph.MinX && oe <= ActiveGraph.MaxX) { PrimaryMarkedPoint = oe - ActiveGraph.MinX; ChangeMarker(PrimaryMarkedPointPlot, true, ActiveGraph.GetOechsleAt(PrimaryMarkedPoint), ActiveGraph.GetPriceAt(PrimaryMarkedPoint)); PriceInput.Text = Math.Round(ActiveGraph.GetPriceAt(PrimaryMarkedPoint), Season.Precision).ToString(); EnableActionButtons(); OechslePricePlot.Refresh(); EnableTextBox(PriceInput); return; } } PrimaryMarkedPoint = -1; ChangeMarker(PrimaryMarkedPointPlot, false); DisableActionButtons(); PriceInput.Text = ""; DisableTextBox(PriceInput); OechslePricePlot.Refresh(); DisableTextBox(PriceInput); } private void OechsleInput_TextChanged(object sender, TextChangedEventArgs evt) { UpdateSelectedPoint(); } private void GebInput_Changed(object sender, RoutedEventArgs evt) { if (Updating) return; var sel = GebInput.IsChecked == true ? SelectedGraphEntry?.GebundenGraph : SelectedGraphEntry?.DataGraph; if (sel != ActiveGraph) ChangeActiveGraph(sel); UpdateSelectedPoint(); } private void PriceInput_TextChanged(object sender, TextChangedEventArgs evt) { if (PrimaryMarkedPoint != -1 && ActiveGraph != null && PriceInput.IsKeyboardFocusWithin == true) { var res = Validator.CheckDecimal(PriceInput, true, 2, Season.Precision); if (res.IsValid && double.TryParse(PriceInput.Text, out double price)) { ActiveGraph.SetPriceAt(PrimaryMarkedPoint, price); PrimaryMarkedPointPlot.Location = new Coordinates(PrimaryMarkedPointPlot.Location.X, price); SetHasChanged(); OechslePricePlot.Refresh(); CheckGebundenTypeFixed(); } } } private void LeftFlatButton_Click(object sender, RoutedEventArgs evt) { if (PrimaryMarkedPoint == -1 || ActiveGraph == null) { return; } ActiveGraph.FlattenGraphLeft(PrimaryMarkedPoint); SetHasChanged(); OechslePricePlot.Refresh(); CheckGebundenTypeFixed(); } private void RightFlatButton_Click(object sender, RoutedEventArgs evt) { if (PrimaryMarkedPoint == -1 || ActiveGraph == null) { return; } ActiveGraph.FlattenGraphRight(PrimaryMarkedPoint); SetHasChanged(); OechslePricePlot.Refresh(); CheckGebundenTypeFixed(); } private void InterpolateButton_Click(object sender, RoutedEventArgs evt) { if (PrimaryMarkedPoint == SecondaryMarkedPoint || PrimaryMarkedPoint == -1 || SecondaryMarkedPoint == -1 || ActiveGraph == null) { return; } ActiveGraph.InterpolateGraph(PrimaryMarkedPoint, SecondaryMarkedPoint); SetHasChanged(); OechslePricePlot.Refresh(); CheckGebundenTypeFixed(); } private void LinearIncreaseButton_Click(object sender, RoutedEventArgs e) { if (PrimaryMarkedPoint == -1 || ActiveGraph == null) { return; } double? priceIncrease = Utils.ShowLinearPriceIncreaseDialog(); if (priceIncrease == null) { return; } ActiveGraph.LinearIncreaseGraphToEnd(PrimaryMarkedPoint, priceIncrease.Value); SetHasChanged(); OechslePricePlot.Refresh(); CheckGebundenTypeFixed(); } private void OechslePricePlot_MouseDown(object sender, MouseEventArgs e) { if (GraphList.SelectedItem == null) return; if (HoverActive) { if (PaymentVar.TestVariant && Keyboard.IsKeyDown(System.Windows.Input.Key.LeftCtrl)) { if (SecondaryMarkedPoint == -1 || ActiveGraph == null || ActiveGraph != Highlighted.Graph) return; SecondaryMarkedPoint = Highlighted.Index; ChangeMarker(SecondaryMarkedPointPlot, true, ActiveGraph.GetOechsleAt(SecondaryMarkedPoint), ActiveGraph.GetPriceAt(SecondaryMarkedPoint)); InterpolateButton.IsEnabled = true; return; } Updating = true; PrimaryMarkedPoint = Highlighted.Index; if (ActiveGraph != Highlighted.Graph) ChangeActiveGraph(Highlighted.Graph); Updating = false; if (PrimaryMarkedPoint == -1 || ActiveGraph == null) return; ChangeMarker(PrimaryMarkedPointPlot, true, ActiveGraph.GetOechsleAt(PrimaryMarkedPoint), ActiveGraph.GetPriceAt(PrimaryMarkedPoint)); Updating = true; OechsleInput.Text = Highlighted.Graph!.GetOechsleAt(Highlighted.Index).ToString(); GebInput.IsChecked = Highlighted.Graph == SelectedGraphEntry?.GebundenGraph; PriceInput.Text = Math.Round(Highlighted.Graph.GetPriceAt(Highlighted.Index), Season.Precision).ToString(); Updating = false; EnableActionButtons(); } else { PrimaryMarkedPoint = -1; SecondaryMarkedPoint = -1; if (SelectedGraphEntry!.GebundenGraph != null) { ChangeActiveGraph(null); } ChangeMarker(PrimaryMarkedPointPlot, false); ChangeMarker(SecondaryMarkedPointPlot, false); OechsleInput.Text = ""; GebInput.IsChecked = false; PriceInput.Text = ""; DisableTextBox(PriceInput); DisableActionButtons(); } } private void OechslePricePlot_MouseMove(object sender, MouseEventArgs e) { MouseChange(e); } private void OechslePricePlot_MouseWheel(object sender, MouseWheelEventArgs e) { MouseChange(e); } private Coordinates GetMouseCoordinates(Point p) { Pixel px = new(p.X, p.Y); var source = PresentationSource.FromVisual(this); if (source?.CompositionTarget != null) { var matrix = source.CompositionTarget.TransformToDevice; px.X *= (float)matrix.M11; px.Y *= (float)matrix.M22; } return OechslePricePlot.Plot.GetCoordinates(px); } private void MouseChange(MouseEventArgs e) { if (GraphList.SelectedItem == null) { return; } var mouseOnData = MouseOnPlot(DataPlot, GetMouseCoordinates(e.GetPosition(OechslePricePlot))); var mouseOnGebunden = MouseOnPlot(GebundenPlot, GetMouseCoordinates(e.GetPosition(OechslePricePlot))); Highlighted = LastHighlighted; if (mouseOnData != null) { ChangeMarker(HighlightedPointPlot, true, mouseOnData.Value.X, mouseOnData.Value.Y); HighlightedPointPlot.IsVisible = true; HoverChanged = true ^ HoverActive; HoverActive = true; HandleTooltip(mouseOnData.Value.X, mouseOnData.Value.Y, mouseOnData.Value.Index, SelectedGraphEntry!.DataGraph, e.GetPosition(OechslePricePlot), e is MouseWheelEventArgs); } else if (mouseOnGebunden != null) { ChangeMarker(HighlightedPointPlot, true, mouseOnGebunden.Value.X, mouseOnGebunden.Value.Y); HighlightedPointPlot.IsVisible = true; HoverChanged = true ^ HoverActive; HoverActive = true; HandleTooltip(mouseOnGebunden.Value.X, mouseOnGebunden.Value.Y, mouseOnGebunden.Value.Index, SelectedGraphEntry!.GebundenGraph!, e.GetPosition(OechslePricePlot), e is MouseWheelEventArgs); } else { ChangeMarker(HighlightedPointPlot, false); HoverChanged = false ^ HoverActive; HoverActive = false; OechslePricePlot.Plot.PlottableList.Remove(TooltipPlot); OechslePricePlot.Refresh(); } } private (double X, double Y, int Index)? MouseOnPlot(Scatter? plot, Coordinates c) { if (plot == null) return null; OechslePricePlot.Refresh(); DataPoint nearestPoint = plot.Data.GetNearest(c, OechslePricePlot.Plot.LastRender, 5); return nearestPoint.IsReal ? (nearestPoint.X, nearestPoint.Y, nearestPoint.Index) : null; } private void HandleTooltip(double pointX, double pointY, int pointIndex, Graph g, Point p, bool force) { if (force || LastHighlighted != Highlighted || HoverChanged) { OechslePricePlot.Plot.PlottableList.Remove(TooltipPlot); if (TooltipInput.IsChecked == true) { Coordinates mouseLocation = GetMouseCoordinates(new(p.X, p.Y - 30)); TooltipPlot = OechslePricePlot.Plot.Add.Text($"Oechsle: {pointX:N2}, Preis: {Math.Round(pointY, Season.Precision)} {CurrencySymbol}/kg", mouseLocation.X, mouseLocation.Y); TooltipPlot.LabelFontSize = 12; TooltipPlot.LabelBold = true; TooltipPlot.LabelBorderColor = Colors.Black; TooltipPlot.LabelBorderWidth = 2; TooltipPlot.LabelBackgroundColor = Colors.White; TooltipPlot.LabelPadding = 10; TooltipPlot.LabelAlignment = Alignment.MiddleLeft; } LastHighlighted = (g, pointIndex); HoverChanged = false; OechslePricePlot.Refresh(); } } private int GetMaxGraphId() { return GraphEntries.Count == 0 ? 0 : GraphEntries.Select(g => g.Id).Max(); } private void AddButton_Click(object sender, RoutedEventArgs e) { GraphEntry newGraphEntry = new(GetMaxGraphId() + 1, Season.Precision, BillingData.CurveMode.Oe); GraphEntries.Add(newGraphEntry); SetHasChanged(); GraphList.Items.Refresh(); GraphList.SelectedItem = newGraphEntry; } private void CopyButton_Click(object sender, RoutedEventArgs e) { if (SelectedGraphEntry == null) return; GraphEntry newGraphEntry = SelectedGraphEntry.Copy(GetMaxGraphId() + 1); GraphEntries.Add(newGraphEntry); SetHasChanged(); GraphList.Items.Refresh(); GraphList.SelectedItem = newGraphEntry; } private void DeleteButton_Click(object sender, RoutedEventArgs e) { if (SelectedGraphEntry == null) return; var r = MessageBox.Show( $"Soll die Kurve {SelectedGraphEntry.Id} (verwendet in folgenden Verträgen: {SelectedGraphEntry.VaributeStringSimple}) wirklich gelöscht werden?", "Kurve löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No); if (r == MessageBoxResult.Yes) { GraphEntries.Remove(SelectedGraphEntry); SetHasChanged(); GraphList.Items.Refresh(); OechslePricePlot.IsEnabled = false; } } private async void SaveButton_Click(object sender, RoutedEventArgs e) { SaveButton.IsEnabled = false; Mouse.OverrideCursor = Cursors.AppStarting; try { using (var ctx = new AppDbContext()) { var origData = BillingData.FromJson(PaymentVar.Data); var data = BillingData.FromGraphEntries(GraphEntries, origData, Utils.GetVaributes(ctx, Year), AllVaributesAssigned, AllVaributesAssignedAbgew); PaymentVar.Data = data.ToJsonString(); ctx.Update(PaymentVar); await ctx.SaveChangesAsync(); } LockContext = false; App.HintContextChange(); } catch (Exception exc) { var str = "Der Eintrag konnte nicht in der Datenbank gespeichert werden!\n\n" + exc.Message; if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message; MessageBox.Show(str, "Auszahlungsvariante speichern", MessageBoxButton.OK, MessageBoxImage.Error); SaveButton.IsEnabled = true; return; } finally { Mouse.OverrideCursor = null; } LockContext = true; SetHasChanged(false); } private void EnableTextBox(TextBox u) { if (PaymentVar.TestVariant || u == OechsleInput) { u.IsEnabled = true; u.IsReadOnly = false; } } private void DisableTextBox(TextBox u) { u.IsEnabled = false; u.IsReadOnly = true; } private void ChangeActiveGraph(Graph? g) { if (g != null && g == SelectedGraphEntry?.DataGraph) { EnableTextBox(OechsleInput); if (SelectedGraphEntry?.GebundenGraph != null) ChangeLineWidth(DataPlot, 4); ChangeLineWidth(GebundenPlot, 1); GebInput.IsEnabled = SelectedGraphEntry?.GebundenGraph != null; GebInput.IsChecked = false; } else if (g != null && g == SelectedGraphEntry?.GebundenGraph) { EnableTextBox(OechsleInput); ChangeLineWidth(GebundenPlot, 4); ChangeLineWidth(DataPlot, 1); GebInput.IsEnabled = SelectedGraphEntry?.GebundenGraph != null; GebInput.IsChecked = true; } else { DisableTextBox(OechsleInput); DisableTextBox(PriceInput); OechsleInput.Text = ""; GebInput.IsEnabled = false; GebInput.IsChecked = false; PriceInput.Text = ""; ChangeLineWidth(DataPlot, 1); ChangeLineWidth(GebundenPlot, 1); } ActiveGraph = g; } private void ChangeLineWidth(Scatter? p, double lineWidth) { if (p != null) { p.LineWidth = (float)lineWidth; } } private void GraphList_SelectionChanged(object sender, SelectionChangedEventArgs e) { RefreshInputs(); } private void GebundenFlatBonus_TextChanged(object sender, TextChangedEventArgs e) { if (FillingInputs) return; var r = Validator.CheckDecimal(GebundenFlatBonus, true, 2, Season.Precision); if (r.IsValid && SelectedGraphEntry != null) { SelectedGraphEntry.GebundenFlatBonus = double.Parse(GebundenFlatBonus.Text); ResetPlot(); InitPlot(); } } private void VaributeInput_Changed(object sender, SelectionChangedEventArgs evt) { if (FillingInputs) return; var isOpen = VaributeInput.IsDropDownOpen; foreach (var i in evt.AddedItems) { if (i is not Varibute v) continue; if (RemoveVaributeFromOthers(v.ToString())) { if (AbgewertetInput.IsChecked == true) { v.AssignedAbgewGraphId = SelectedGraphEntry?.Id; } else { v.AssignedGraphId = SelectedGraphEntry?.Id; } } else { VaributeInput.SelectedItems.Remove(v); } } foreach (var i in evt.RemovedItems) { if (i is not Varibute v) continue; if (AbgewertetInput.IsChecked == true) { v.AssignedAbgewGraphId = null; } else { v.AssignedGraphId = null; } } SelectedGraphEntry!.Vaributes = VaributeInput.SelectedItems.Cast().ToList(); SetHasChanged(); GraphList.Items.Refresh(); VaributeInput.Items.Refresh(); VaributeInput.IsDropDownOpen = isOpen; } private bool RemoveVaributeFromOthers(string? varibute) { if (varibute == null) return true; foreach (var ge in GraphEntries) { if (ge != SelectedGraphEntry && ge.Abgewertet == SelectedGraphEntry?.Abgewertet) { var toRemove = ge.Vaributes.Where(c => c.Listing.Equals(varibute)).ToList(); if (toRemove.Count == 0) continue; var r = MessageBox.Show($"Achtung: {string.Join(", ", toRemove)} ist bereits in Kurve {ge.Id} in Verwendung!\nSoll die Zuweisung dort entfernt werden?", "Entfernen bestätigen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No); if (r != MessageBoxResult.Yes) { return false; } ge.Vaributes.RemoveAll(c => c.Listing.Equals(varibute)); } } return true; } private void AbgewertetInput_Changed(object sender, RoutedEventArgs e) { if (FillingInputs) return; if (SelectedGraphEntry == null) return; SelectedGraphEntry.Abgewertet = AbgewertetInput.IsChecked == true; SetHasChanged(); GraphList.Items.Refresh(); } private void GebundenType_Checked(object sender, RoutedEventArgs e) { if (FillingInputs) return; if (SelectedGraphEntry == null) { DisableTextBox(GebundenFlatBonus); return; } if (GebundenTypeNone.IsChecked == true) { SelectedGraphEntry.RemoveGebundenGraph(); DisableTextBox(GebundenFlatBonus); } else if (GebundenTypeFixed.IsChecked == true) { SelectedGraphEntry.GebundenFlatBonus = double.TryParse(GebundenFlatBonus.Text, out var val) ? val : 0.1; SelectedGraphEntry.AddGebundenGraph(); EnableTextBox(GebundenFlatBonus); } else if (GebundenTypeGraph.IsChecked == true) { SelectedGraphEntry.AddGebundenGraph(); DisableTextBox(GebundenFlatBonus); } SetHasChanged(); RefreshInputs(); } private void CheckGebundenTypeFixed() { FillingInputs = true; if (SelectedGraphEntry?.GebundenFlatBonus is double bonus) { GebundenTypeFixed.IsChecked = true; GebundenFlatBonus.Text = $"{bonus}"; EnableTextBox(GebundenFlatBonus); } else if (SelectedGraphEntry?.GebundenGraph != null) { GebundenTypeGraph.IsChecked = true; GebundenFlatBonus.Text = ""; DisableTextBox(GebundenFlatBonus); } FillingInputs = false; } } }