Files
elwig/Elwig/Windows/AdministrationWindow.cs
Lorenz Stechauner 4403754ada
All checks were successful
Test / Run tests (push) Successful in 2m23s
MemberAdminWindow: Fix error when saving telephone numbers
2024-08-01 15:57:49 +02:00

600 lines
25 KiB
C#

using Elwig.Helpers;
using Elwig.Models.Entities;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Windows.Input;
namespace Elwig.Windows {
public abstract class AdministrationWindow : ContextWindow {
protected Control[] ExemptInputs { private get; set; }
protected Control[] RequiredInputs { private get; set; }
private bool _isEditing;
private bool _isCreating;
public bool IsEditing {
get { return _isEditing; }
set {
_isEditing = value;
LockContext = IsEditing || IsCreating;
}
}
public bool IsCreating {
get { return _isCreating; }
set {
_isCreating = value;
LockContext = IsEditing || IsCreating;
}
}
protected bool DoShowWarningWindows = true;
protected bool IsClosing { get; private set; }
private TextBox[] TextBoxInputs;
private TextBox[] PlzInputs;
private ComboBox[] ComboBoxInputs;
private ComboBox[] PlzOrtInputs;
private ListBox[] ListBoxInputs;
private CheckBox[] CheckBoxInputs;
private RadioButton[] RadioButtonInputs;
private readonly Dictionary<Control, bool> Valid;
private readonly Dictionary<Control, int?> OriginalValues;
private readonly Dictionary<Control, int?> DefaultValues;
private readonly RoutedCommand AltInsert = new("AltInsert", typeof(AdministrationWindow), [new KeyGesture(Key.Insert, ModifierKeys.Alt)]);
private readonly RoutedCommand AltDelete = new("AltDelete", typeof(AdministrationWindow), [new KeyGesture(Key.Delete, ModifierKeys.Alt)]);
private readonly RoutedCommand CtrlZ = new("CtrlZ", typeof(AdministrationWindow), [new KeyGesture(Key.Z, ModifierKeys.Control)]);
private readonly RoutedCommand CtrlS = new("CtrlS", typeof(AdministrationWindow), [new KeyGesture(Key.S, ModifierKeys.Control)]);
private readonly RoutedCommand CtrlB = new("CtrlB", typeof(AdministrationWindow), [new KeyGesture(Key.B, ModifierKeys.Control)]);
public AdministrationWindow() : base() {
CommandBindings.Add(new CommandBinding(AltInsert, ShortcutNew));
CommandBindings.Add(new CommandBinding(AltDelete, ShortcutDelete));
CommandBindings.Add(new CommandBinding(CtrlZ, ShortcutReset));
CommandBindings.Add(new CommandBinding(CtrlS, ShortcutSave));
CommandBindings.Add(new CommandBinding(CtrlB, ShortcutEdit));
IsEditing = false;
IsCreating = false;
ExemptInputs = [];
RequiredInputs = [];
TextBoxInputs = [];
PlzInputs = [];
ComboBoxInputs = [];
ListBoxInputs = [];
PlzOrtInputs = [];
CheckBoxInputs = [];
RadioButtonInputs = [];
Valid = [];
OriginalValues = [];
DefaultValues = [];
Closing += OnClosing;
Loaded -= base.OnLoaded;
Loaded += OnLoaded;
Loaded += base.OnLoaded;
}
abstract protected void ShortcutNew();
abstract protected void ShortcutDelete();
abstract protected void ShortcutReset();
abstract protected void ShortcutSave();
abstract protected void ShortcutEdit();
private void ShortcutNew(object sender, EventArgs evt) { ShortcutNew(); }
private void ShortcutDelete(object sender, EventArgs evt) { ShortcutDelete(); }
private void ShortcutReset(object sender, EventArgs evt) { ShortcutReset(); }
private void ShortcutSave(object sender, EventArgs evt) { ShortcutSave(); }
private void ShortcutEdit(object sender, EventArgs evt) { ShortcutEdit(); }
private new void OnLoaded(object sender, RoutedEventArgs evt) {
TextBoxInputs = ControlUtils.FindAllChildren<TextBox>(this, ExemptInputs).ToArray();
ComboBoxInputs = ControlUtils.FindAllChildren<ComboBox>(this, ExemptInputs).ToArray();
CheckBoxInputs = ControlUtils.FindAllChildren<CheckBox>(this, ExemptInputs).ToArray();
ListBoxInputs = ControlUtils.FindAllChildren<ListBox>(this, ExemptInputs).ToArray();
RadioButtonInputs = ControlUtils.FindAllChildren<RadioButton>(this, ExemptInputs).ToArray();
PlzInputs = ControlUtils.FindAllChildren<TextBox>(this).Where(tb => "PLZ".Equals(tb.Tag)).ToArray();
PlzOrtInputs = PlzInputs.Select(tb => ControlUtils.FindNextSibling<ComboBox>(tb) ?? throw new MissingMemberException()).ToArray();
foreach (var tb in TextBoxInputs)
Valid[tb] = true;
foreach (var cb in ComboBoxInputs)
cb.SelectionChanged += ComboBox_SelectionChanged;
foreach (var lb in ListBoxInputs)
lb.SelectionChanged += ComboBox_SelectionChanged;
}
private void OnClosing(object? sender, CancelEventArgs evt) {
if ((IsCreating || IsEditing) && HasChanged) {
var r = MessageBox.Show("Soll das Fenster wirklich geschlossen werden?", "Schließen bestätigen",
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (r != MessageBoxResult.Yes) {
evt.Cancel = true;
return;
}
}
IsClosing = true;
}
private ComboBox GetPlzOrtInput(TextBox input) {
return PlzOrtInputs[Array.IndexOf(PlzInputs, input)];
}
abstract protected void UpdateButtons();
protected override async Task OnRenewContext(AppDbContext ctx) {
for (int i = 0; i < PlzInputs.Length; i++)
await UpdatePlz(PlzInputs[i], PlzOrtInputs[i]);
}
protected void ValidateInput(Control input, bool valid) {
Valid[input] = valid;
}
protected bool SenderIsRequired(object sender) {
return (sender is Control c) && RequiredInputs.Contains(c);
}
protected void FinishInputFilling() {
FillOriginalValues();
ValidateDefaultValues();
ValidateRequiredInputs();
}
protected void ClearInputStates() {
foreach (var tb in TextBoxInputs)
ControlUtils.ClearInputState(tb);
foreach (var cb in ComboBoxInputs)
ControlUtils.ClearInputState(cb);
foreach (var lb in ListBoxInputs)
ControlUtils.ClearInputState(lb);
foreach (var cb in CheckBoxInputs)
ControlUtils.ClearInputState(cb);
foreach (var rb in RadioButtonInputs)
ControlUtils.ClearInputState(rb);
}
protected void ValidateRequiredInputs() {
foreach (var input in RequiredInputs) {
if (input is TextBox tb && tb.Text.Length == 0) {
ControlUtils.SetInputInvalid(input);
Valid[input] = false;
} else if (input is ComboBox cb && cb.SelectedItem == null && cb.ItemsSource != null && cb.ItemsSource.Cast<object>().Any()) {
ControlUtils.SetInputInvalid(input);
} else if (input is ListBox lb && lb.SelectedItem == null && lb.ItemsSource != null && lb.ItemsSource.Cast<object>().Any()) {
ControlUtils.SetInputInvalid(input);
} else if (input is CheckBox ckb && ((ckb.IsThreeState && ckb.IsChecked == null) || (!ckb.IsThreeState && ckb.IsChecked != true))) {
ControlUtils.SetInputInvalid(input);
Valid[input] = false;
} else if (input is RadioButton rb && rb.IsChecked != true) {
ControlUtils.SetInputInvalid(input);
Valid[input] = false;
}
}
}
protected void ValidateDefaultValues() {
foreach (var input in DefaultValues.Keys) {
if (InputIsNotDefault(input))
ControlUtils.SetInputNotDefault(input);
}
}
protected void LockInputs() {
foreach (var tb in TextBoxInputs)
tb.IsReadOnly = true;
foreach (var cb in ComboBoxInputs)
cb.IsEnabled = false;
foreach (var lb in ListBoxInputs)
lb.IsEnabled = false;
foreach (var cb in CheckBoxInputs)
cb.IsEnabled = false;
foreach (var rb in RadioButtonInputs)
rb.IsEnabled = false;
}
protected void UnlockInputs() {
foreach (var tb in TextBoxInputs)
tb.IsReadOnly = false;
foreach (var cb in ComboBoxInputs)
cb.IsEnabled = true;
foreach (var lb in ListBoxInputs)
lb.IsEnabled = true;
foreach (var cb in CheckBoxInputs)
cb.IsEnabled = true;
foreach (var rb in RadioButtonInputs)
rb.IsEnabled = true;
}
protected void ClearOriginalValues() {
OriginalValues.Clear();
}
protected void ClearDefaultValues() {
DefaultValues.Clear();
}
protected void FillOriginalValues() {
foreach (var tb in TextBoxInputs)
OriginalValues[tb] = ControlUtils.GetInputHashCode(tb);
foreach (var cb in ComboBoxInputs)
OriginalValues[cb] = ControlUtils.GetInputHashCode(cb);
foreach (var lb in ListBoxInputs)
OriginalValues[lb] = ControlUtils.GetInputHashCode(lb);
foreach (var cb in CheckBoxInputs)
OriginalValues[cb] = ControlUtils.GetInputHashCode(cb);
foreach (var rb in RadioButtonInputs)
OriginalValues[rb] = ControlUtils.GetInputHashCode(rb);
}
protected void SetOriginalValue(Control input, object? value) {
OriginalValues[input] = Utils.GetEntityIdentifier(value);
if (InputHasChanged(input)) {
ControlUtils.SetInputChanged(input);
} else {
ControlUtils.ClearInputState(input);
}
}
protected void SetOriginalValue(Control input) {
SetOriginalValue(input, ControlUtils.GetInputHashCode(input));
}
protected void UnsetOriginalValue(Control input) {
OriginalValues.Remove(input);
ControlUtils.ClearInputState(input);
}
protected void SetDefaultValue(Control input, object? value) {
DefaultValues[input] = Utils.GetEntityIdentifier(value);
if (!InputHasChanged(input)) {
if (InputIsNotDefault(input)) {
ControlUtils.SetInputNotDefault(input);
} else {
ControlUtils.ClearInputState(input);
}
}
}
protected void SetDefaultValue(Control input) {
SetDefaultValue(input, ControlUtils.GetInputHashCode(input));
}
protected void UnsetDefaultValue(Control input) {
DefaultValues.Remove(input);
if (!InputHasChanged(input)) {
ControlUtils.ClearInputState(input);
}
}
protected void ClearInputs(bool validate = true) {
foreach (var tb in TextBoxInputs) {
tb.Text = "";
var binding = tb.GetBindingExpression(TextBox.TextProperty);
binding?.UpdateSource();
}
foreach (var cb in ComboBoxInputs) {
cb.SelectedItem = null;
var binding = cb.GetBindingExpression(ComboBox.SelectedItemProperty);
binding?.UpdateSource();
}
foreach (var lb in ListBoxInputs)
lb.SelectedItems.Clear();
foreach (var cb in CheckBoxInputs) {
cb.IsChecked = cb.IsThreeState ? null : false;
var binding = cb.GetBindingExpression(CheckBox.IsCheckedProperty);
binding?.UpdateSource();
}
foreach (var rb in RadioButtonInputs) {
rb.IsChecked = rb.IsThreeState ? null : false;
var binding = rb.GetBindingExpression(RadioButton.IsCheckedProperty);
binding?.UpdateSource();
}
if (validate) ValidateRequiredInputs();
}
protected bool IsValid => Valid.All(kv => kv.Value);
protected bool GetInputValid(Control input) {
return Valid[input];
}
protected bool InputHasChanged(Control input) {
if (!OriginalValues.TryGetValue(input, out int? original)) {
return false;
} else {
var current = ControlUtils.GetInputHashCode(input);
return original != current;
}
}
protected bool InputIsNotDefault(Control input) {
if (!DefaultValues.TryGetValue(input, out int? defaultValue)) {
return false;
} else {
var current = ControlUtils.GetInputHashCode(input);
return defaultValue != current;
}
}
protected bool HasChanged =>
IsEditing && (
!IsValid ||
TextBoxInputs.Any(InputHasChanged) ||
ComboBoxInputs.Any(InputHasChanged) ||
ListBoxInputs.Any(InputHasChanged) ||
CheckBoxInputs.Any(InputHasChanged) ||
RadioButtonInputs.Any(InputHasChanged)
) || IsCreating && (
TextBoxInputs.Any(i => InputIsNotDefault(i) || (!i.IsReadOnly && i.Text != "")) ||
ComboBoxInputs.Any(i => InputIsNotDefault(i) || (i.IsEnabled && i.SelectedItem != null)) ||
ListBoxInputs.Any(i => InputIsNotDefault(i) || i.SelectedItem != null) ||
CheckBoxInputs.Any(InputIsNotDefault) ||
RadioButtonInputs.Any(InputIsNotDefault)
);
protected async Task UpdatePlz(TextBox plzInput, ComboBox ortInput) {
var plzInputValid = Validator.CheckPlz(plzInput, RequiredInputs.Contains(plzInput)).IsValid;
List<AT_PlzDest> list = [];
if (plzInputValid && plzInput.Text.Length == 4) {
var plz = int.Parse(plzInput.Text);
using var ctx = new AppDbContext();
list = await ctx.PlzDestinations
.Where(p => p.Plz == plz)
.Include(p => p.Ort)
.ToListAsync();
}
ControlUtils.RenewItemsSource(ortInput, list);
if (ortInput.SelectedItem == null && list.Count == 1)
ortInput.SelectedItem = list[0];
UpdateComboBox(ortInput);
}
protected static void InitializeDelayTimer(TextBox tb, Action<object, TextChangedEventArgs> handler) {
var timer = new DispatcherTimer {
Interval = TimeSpan.FromMilliseconds(250)
};
timer.Tick += (object? sender, EventArgs evt) => {
timer.Stop();
var (oSender, oEvent) = ((object, TextChangedEventArgs))timer.Tag;
handler(oSender, oEvent);
};
tb.TextChanged += (object sender, TextChangedEventArgs evt) => {
timer.Stop();
timer.Tag = (sender, evt);
timer.Start();
};
}
protected bool InputTextChanged(TextBox input) {
return InputTextChanged(input, new ValidationResult(true, null));
}
protected bool InputTextChanged(TextBox input, Func<TextBox, bool, ValidationResult> checker) {
return InputTextChanged(input, checker(input, SenderIsRequired(input)));
}
protected bool InputTextChanged(TextBox input, ValidationResult res) {
ValidateInput(input, res.IsValid);
if (res.IsValid) {
if (InputHasChanged(input)) {
ControlUtils.SetInputChanged(input);
} else if (InputIsNotDefault(input)) {
ControlUtils.SetInputNotDefault(input);
} else {
ControlUtils.ClearInputState(input);
}
} else {
ControlUtils.SetInputInvalid(input);
}
UpdateButtons();
return res.IsValid;
}
protected bool InputLostFocus(TextBox input, Func<TextBox, bool, ValidationResult> checker, string? msg = null) {
return InputLostFocus(input, checker(input, SenderIsRequired(input)), msg);
}
protected bool InputLostFocus(TextBox input, ValidationResult res, string? msg = null) {
if (DoShowWarningWindows && !res.IsValid && !IsClosing && (IsEditing || IsCreating))
MessageBox.Show(res.ErrorContent?.ToString(), msg ?? res.ErrorContent?.ToString(), MessageBoxButton.OK, MessageBoxImage.Warning);
return res.IsValid;
}
protected void CheckBox_Changed(object sender, RoutedEventArgs evt) {
var input = (CheckBox)sender;
if (SenderIsRequired(input) && ((input.IsThreeState && input.IsChecked == null) || (!input.IsThreeState && input.IsChecked != true))) {
ValidateInput(input, false);
ControlUtils.SetInputInvalid(input);
} else {
ValidateInput(input, true);
if (InputHasChanged(input)) {
ControlUtils.SetInputChanged(input);
} else if (InputIsNotDefault(input)) {
ControlUtils.SetInputNotDefault(input);
} else {
ControlUtils.ClearInputState(input);
}
}
UpdateButtons();
}
protected void RadioButton_Changed(object sender, RoutedEventArgs evt) {
var input = (RadioButton)sender;
if (SenderIsRequired(input) && input.IsChecked != true) {
ValidateInput(input, false);
ControlUtils.SetInputInvalid(input);
} else {
ValidateInput(input, true);
if (InputHasChanged(input)) {
ControlUtils.SetInputChanged(input);
} else if (InputIsNotDefault(input)) {
ControlUtils.SetInputNotDefault(input);
} else {
ControlUtils.ClearInputState(input);
}
}
UpdateButtons();
}
protected void TextBox_TextChanged(object sender, RoutedEventArgs? evt) {
var input = (Control)sender;
var tb = input as TextBox;
if (SenderIsRequired(input) && tb?.Text.Length == 0) {
ValidateInput(input, false);
ControlUtils.SetInputInvalid(input);
} else {
ValidateInput(input, true);
if (InputHasChanged(input)) {
ControlUtils.SetInputChanged(input);
} else if (InputIsNotDefault(input)) {
ControlUtils.SetInputNotDefault(input);
} else {
ControlUtils.ClearInputState(input);
}
}
UpdateButtons();
}
private void UpdateComboBox(Control input) {
bool valid = false;
if (input is ComboBox cb) {
valid = cb.ItemsSource == null || cb.SelectedItem != null || !RequiredInputs.Contains(input) || !cb.ItemsSource.Cast<object>().Any();
} else if (input is ListBox lb) {
valid = lb.ItemsSource == null || lb.SelectedItem != null || !RequiredInputs.Contains(input) || !lb.ItemsSource.Cast<object>().Any();
}
if (valid) {
ValidateInput(input, true);
if (InputHasChanged(input)) {
ControlUtils.SetInputChanged(input);
} else if (InputIsNotDefault(input)) {
ControlUtils.SetInputNotDefault(input);
} else {
ControlUtils.ClearInputState(input);
}
} else {
ValidateInput(input, false);
ControlUtils.SetInputInvalid(input);
}
UpdateButtons();
}
protected void ComboBox_SelectionChanged(object sender, RoutedEventArgs? evt) {
UpdateComboBox((Control)sender);
}
protected void IntegerInput_TextChanged(object sender, TextChangedEventArgs? evt) {
// FIXME
InputTextChanged((TextBox)sender, Validator.CheckInteger);
}
protected void DecimalInput_TextChanged(object sender, TextChangedEventArgs? evt) {
// FIXME
InputTextChanged((TextBox)sender, Validator.CheckDecimal);
}
protected void PartialDateInput_TextChanged(object sender, TextChangedEventArgs? evt) {
InputTextChanged((TextBox)sender, Validator.CheckPartialDate);
}
protected void PartialDateInput_LostFocus(object sender, RoutedEventArgs? evt) {
InputLostFocus((TextBox)sender, Validator.CheckPartialDate);
}
protected void DateInput_TextChanged(object sender, TextChangedEventArgs? evt) {
InputTextChanged((TextBox)sender, Validator.CheckDate);
}
protected void DateInput_LostFocus(object sender, RoutedEventArgs? evt) {
InputLostFocus((TextBox)sender, Validator.CheckDate);
}
protected void TimeInput_TextChanged(object sender, TextChangedEventArgs? evt) {
InputTextChanged((TextBox)sender, Validator.CheckTime);
}
protected void TimeInput_LostFocus(object sender, RoutedEventArgs? evt) {
InputLostFocus((TextBox)sender, Validator.CheckTime);
}
protected async void PlzInput_TextChanged(object sender, TextChangedEventArgs? evt) {
var plz = (TextBox)sender;
InputTextChanged(plz, Validator.CheckPlz);
if ("PLZ".Equals(plz.Tag))
await UpdatePlz(plz, GetPlzOrtInput(plz));
}
protected async void PlzInput_LostFocus(object sender, RoutedEventArgs? evt) {
var plz = (TextBox)sender;
InputLostFocus(plz, Validator.CheckPlz);
if ("PLZ".Equals(plz.Tag))
await UpdatePlz(plz, GetPlzOrtInput(plz));
}
protected void EmailAddressInput_TextChanged(object sender, TextChangedEventArgs? evt) {
InputTextChanged((TextBox)sender, Validator.CheckEmailAddress);
}
protected void EmailAddressInput_LostFocus(object sender, RoutedEventArgs? evt) {
InputLostFocus((TextBox)sender, Validator.CheckEmailAddress);
}
protected void PhoneNrInput_TextChanged(object sender, TextChangedEventArgs? evt) {
InputTextChanged((TextBox)sender, Validator.CheckPhoneNumber);
}
protected void PhoneNrInput_LostFocus(object sender, RoutedEventArgs? evt) {
InputLostFocus((TextBox)sender, Validator.CheckPhoneNumber);
}
protected void IbanInput_TextChanged(object sender, TextChangedEventArgs? evt) {
InputTextChanged((TextBox)sender, Validator.CheckIban);
}
protected void IbanInput_LostFocus(object sender, RoutedEventArgs? evt) {
InputLostFocus((TextBox)sender, Validator.CheckIban);
}
protected void BicInput_TextChanged(object sender, TextChangedEventArgs? evt) {
InputTextChanged((TextBox)sender, Validator.CheckBic);
}
protected void BicInput_LostFocus(object sender, RoutedEventArgs? evt) {
InputLostFocus((TextBox)sender, Validator.CheckBic);
}
protected void UstIdNrInput_TextChanged(object sender, TextChangedEventArgs? evt) {
InputTextChanged((TextBox)sender, Validator.CheckUstIdNr);
}
protected void UstIdNrInput_LostFocus(object sender, RoutedEventArgs? evt) {
InputLostFocus((TextBox)sender, Validator.CheckUstIdNr);
}
protected void LfbisNrInput_TextChanged(object sender, TextChangedEventArgs? evt) {
InputTextChanged((TextBox)sender, Validator.CheckLfbisNr);
}
protected void LfbisNrInput_LostFocus(object sender, RoutedEventArgs? evt) {
InputLostFocus((TextBox)sender, Validator.CheckLfbisNr);
}
protected void UpperCaseInput_TextChanged(object sender, TextChangedEventArgs? evt) {
InputTextChanged((TextBox)sender, Validator.CheckUpperCase);
}
protected void UpperCaseInput_LostFocus(object sender, RoutedEventArgs? evt) {
InputLostFocus((TextBox)sender, Validator.CheckUpperCase);
}
protected void AreaComTypeDetailsButton_Click(object sender, RoutedEventArgs? evt) {
App.FocusBaseDataAreaComType();
}
}
}