Windows: Add OriginHierarchyWindow

This commit is contained in:
2023-11-24 23:38:55 +01:00
parent fb4dc613ae
commit c25bfc9f1b
14 changed files with 353 additions and 10 deletions

View File

@ -84,6 +84,12 @@
</DataTemplate.Triggers>
</DataTemplate>
<DataTemplate x:Key="WineOriginTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding HkIdLevel}" MinWidth="70" Margin="0,0,10,0"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
<ControlTemplate x:Key="WineOriginTemplateSimple">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
@ -95,7 +101,7 @@
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</ControlTemplate>
<DataTemplate x:Key="WineOriginTemplate">
<DataTemplate x:Key="WineOriginComboTemplate">
<Control x:Name="Control" Focusable="False" Template="{StaticResource WineOriginTemplateExtended}"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ComboBoxItem}}, Path=IsSelected}" Value="{x:Null}">
@ -103,5 +109,31 @@
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<DataTemplate x:Key="GemTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Gkz, StringFormat='{} ({0:00000})'}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="WbKgTemplate">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Width="250">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding KgNr, StringFormat='{}({0:00000})'}"/>
</TextBlock>
<TextBlock Text="{Binding Gem.WbGem.Origin.Name}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="WbKgGlTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Width="220">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding KgNr, StringFormat='{}({0:00000})'}"/>
</TextBlock>
<TextBlock Text="{Binding WbKg.Gl.Name}"/>
</StackPanel>
</DataTemplate>
</Application.Resources>
</Application>

View File

@ -15,6 +15,7 @@ using System.Reflection;
using Elwig.Helpers.Printing;
using Elwig.Windows;
using Elwig.Dialogs;
using System.Threading.Tasks;
namespace Elwig {
public partial class App : Application {
@ -175,6 +176,13 @@ namespace Elwig {
}
}
public static async Task HintContextChange() {
foreach (Window w in CurrentApp.Windows) {
if (w is not ContextWindow c) continue;
await c.HintContextChange();
}
}
private static T FocusWindow<T>(Func<T> constructor, Predicate<T>? selector = null) where T : Window {
foreach (Window w in CurrentApp.Windows) {
if (w is T t && (selector == null || selector(t))) {
@ -218,5 +226,15 @@ namespace Elwig {
public static DeliveryConfirmationsWindow FocusDeliveryConfirmations(int year) {
return FocusWindow<DeliveryConfirmationsWindow>(() => new(year), w => w.Year == year);
}
public static OriginHierarchyWindow FocusOriginHierarchy() {
return FocusWindow<OriginHierarchyWindow>(() => new());
}
public static OriginHierarchyWindow FocusOriginHierarchyKg(int kgnr) {
var w = FocusOriginHierarchy();
w.FocusKgNr(kgnr);
return w;
}
}
}

View File

@ -27,6 +27,8 @@ namespace Elwig.Helpers {
public DbSet<WineVar> WineVarieties { get; private set; }
public DbSet<ClientParam> ClientParameters { get; private set; }
public DbSet<WbGl> WbGls { get; private set; }
public DbSet<WbGem> WbGems { get; private set; }
public DbSet<WbKg> WbKgs { get; private set; }
public DbSet<WbRd> WbRde { get; private set; }
public DbSet<WineAttr> WineAttributes { get; private set; }

View File

@ -183,6 +183,15 @@ namespace Elwig.Helpers {
SelectComboBoxItem(cb, getId, getId(item));
}
public static void SelectListBoxItem(ListBox lb, Func<object?, object?> getId, object? id) {
lb.SelectedItem = GetItemFromSource(lb.ItemsSource, getId, id);
lb.ScrollIntoView(lb.SelectedItem);
}
public static void SelectListBoxItem(ListBox lb, object? item, Func<object?, object?> getId) {
SelectListBoxItem(lb, getId, getId(item));
}
public static IEnumerable<object?> GetItemsFromSource(IEnumerable source, Func<object?, object?> getId, IEnumerable<object?> ids) {
if (source == null)
return Array.Empty<object>();

View File

@ -17,6 +17,6 @@ namespace Elwig.Models.Entities {
public virtual AT_Gem Gem { get; private set; }
[InverseProperty("AtKg")]
public virtual WbKg WbKg { get; private set; }
public virtual WbKg? WbKg { get; private set; }
}
}

View File

@ -573,10 +573,6 @@ namespace Elwig.Windows {
InputLostFocus((TextBox)sender, Validator.CheckUpperCase);
}
protected void KgDetailsButton_Click(object sender, RoutedEventArgs evt) {
// TODO open origin window
}
protected void AreaComTypeDetailsButton_Click(object sender, RoutedEventArgs evt) {
App.FocusBaseDataAreaComType();
}

View File

@ -401,6 +401,14 @@ namespace Elwig.Windows {
ComboBox_SelectionChanged(sender, evt);
}
private void KgDetailsButton_Click(object sender, RoutedEventArgs evt) {
if (KgInput.SelectedItem is AT_Kg kg) {
App.FocusOriginHierarchyKg(kg.KgNr);
} else {
App.FocusOriginHierarchy();
}
}
private void RdInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
RdAddButton.IsEnabled = RdInput.SelectedIndex == -1;
}

View File

@ -545,6 +545,10 @@
</TabItem>
</TabControl>
<Button x:Name="OriginButton" Content="Herkunftshierarchie"
HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="10,10,10,10" Width="150"
Click="OriginButton_Click"/>
<Button x:Name="EditButton" Content="Bearbeiten"
HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,10" Width="120"
Click="EditButton_Click"/>

View File

@ -167,6 +167,10 @@ namespace Elwig.Windows {
SeasonModifierDeleteButton.IsEnabled = SeasonModifierList.SelectedIndex != -1;
}
private void OriginButton_Click(object sender, RoutedEventArgs evt) {
App.FocusOriginHierarchy();
}
private void EditButton_Click(object sender, RoutedEventArgs evt) {
IsEditing = true;
EditButton.Visibility = Visibility.Hidden;

View File

@ -24,14 +24,18 @@ namespace Elwig.Windows {
Loaded += OnLoaded;
}
private async void OnShouldRenewContext(object? sender, EventArgs evt) {
if (!Context.HasBackendChanged) return;
public async Task HintContextChange() {
_renewPending = true;
if (LockContext) return;
await RenewContext();
}
protected async void OnLoaded(object sender, RoutedEventArgs evt) {
private async void OnShouldRenewContext(object? sender, EventArgs? evt) {
if (!Context.HasBackendChanged) return;
await HintContextChange();
}
protected async void OnLoaded(object? sender, RoutedEventArgs? evt) {
await OnRenewContext();
}

View File

@ -417,7 +417,7 @@
<Label Content="Weinbaugebiet:" Margin="10,10,0,10" Grid.Column="0"/>
<ComboBox x:Name="WineOriginInput" Margin="0,10,10,10" Grid.Column="1"
ItemTemplate="{StaticResource WineOriginTemplate}"/>
ItemTemplate="{StaticResource WineOriginComboTemplate}"/>
<Label Content="Weinbau-KG:" Margin="10,40,0,10" Grid.Column="0"/>
<ComboBox x:Name="WineKgInput" Margin="0,40,10,10" Grid.Column="1"

View File

@ -672,5 +672,13 @@ namespace Elwig.Windows {
base.PhoneNrInput_TextChanged(sender, evt);
UpdatePhoneNrInputVisibility(IsEditing || IsCreating);
}
private void KgDetailsButton_Click(object sender, RoutedEventArgs evt) {
if (DefaultKgInput.SelectedItem is AT_Kg kg) {
App.FocusOriginHierarchyKg(kg.KgNr);
} else {
App.FocusOriginHierarchy();
}
}
}
}

View File

@ -0,0 +1,74 @@
<local:ContextWindow
x:Class="Elwig.Windows.OriginHierarchyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Elwig.Windows"
mc:Ignorable="d"
Title="Herkunftshierarchie - Elwig" Height="800" Width="1200" MinHeight="500" MinWidth="1000">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" MinWidth="300"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="1*" MinWidth="400"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="25"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Label Content="Weinbaugebiete" Margin="10,0,0,0" VerticalAlignment="Top" Grid.RowSpan="3"/>
<ListBox x:Name="WineOrigins" Margin="10,25,0,10" Grid.RowSpan="3"
ItemTemplate="{StaticResource WineOriginTemplate}"
SelectionChanged="WineOrigins_SelectionChanged"/>
<Label Content="Großlagen" Margin="0,0,0,0" VerticalAlignment="Top" Grid.Column="2"/>
<ListBox x:Name="WbGls" Margin="0,25,0,5" Grid.Column="2"
DisplayMemberPath="Name"
SelectionChanged="WbGls_SelectionChanged"/>
<Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Padding="0" Grid.Row="2" Grid.Column="1"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
<Label x:Name="WbGemsHeader" Content="Gemeinden" Margin="0,0,0,0" VerticalAlignment="Top" Grid.Column="2" Grid.Row="2"/>
<ListBox x:Name="WbGems" Margin="0,25,0,10" Grid.Column="2" Grid.Row="2"
ItemTemplate="{StaticResource GemTemplate}" TextSearch.TextPath="Name"
SelectionChanged="WbGems_SelectionChanged"/>
<Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Padding="0" Grid.Column="3"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
<Label x:Name="WbGlKgsHeader" Content="Aktive KG" Margin="0,0,0,0" VerticalAlignment="Top" Grid.Column="4"/>
<Label Content="Weinbaugebiet" Margin="250,0,0,0" VerticalAlignment="Top" Grid.Column="4" Background="White"/>
<ListBox x:Name="WbGlKgs" Margin="0,25,0,5" Grid.Column="4"
ItemTemplate="{StaticResource WbKgTemplate}" TextSearch.TextPath="Name"
SelectionChanged="WbGlKgs_SelectionChanged"/>
<Button x:Name="ActivateKgButton" Content="&#xF0AD;" Grid.Column="4" Grid.Row="1" Height="25" Width="25" Margin="0,0,30,0"
FontFamily="Segoe MDL2 Assets" FontSize="14"
Click="ActivateKgButton_Click"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
<Button x:Name="DeactivateKgButton" Content="&#xF0AE;" Grid.Column="4" Grid.Row="1" Height="25" Width="25" Margin="30,0,0,0"
FontFamily="Segoe MDL2 Assets" FontSize="14"
Click="DeactivateKgButton_Click"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
<Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Padding="0" Grid.Row="2" Grid.Column="3"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
<Label x:Name="WbKgsHeader" Content="Verfügbare KG" Margin="0,0,0,0" VerticalAlignment="Top" Grid.Column="4" Grid.Row="2"/>
<Label Content="Zugewiesen zu Großlage" Margin="220,0,0,0" VerticalAlignment="Top" Grid.Column="4" Grid.Row="2" Background="White"/>
<ListBox x:Name="WbKgs" Margin="0,25,0,10" Grid.Column="4" Grid.Row="2"
ItemTemplate="{StaticResource WbKgGlTemplate}" TextSearch.TextPath="Name"
SelectionChanged="WbKgs_SelectionChanged"/>
<Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Padding="0" Grid.Column="5"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
<Label x:Name="WbRdsHeader" Content="Riede" Margin="0,0,0,0" VerticalAlignment="Top" Grid.Column="6" Grid.RowSpan="3"/>
<ListBox x:Name="WbRds" Margin="0,25,10,10" Grid.Column="6" Grid.RowSpan="3"
DisplayMemberPath="Name" TextSearch.TextPath="Name"/>
</Grid>
</local:ContextWindow>

View File

@ -0,0 +1,184 @@
using Elwig.Helpers;
using Elwig.Models.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace Elwig.Windows {
public partial class OriginHierarchyWindow : ContextWindow {
private bool isUpdating = false;
public OriginHierarchyWindow() {
InitializeComponent();
ActivateKgButton.IsEnabled = false;
DeactivateKgButton.IsEnabled = false;
}
protected override async Task OnRenewContext() {
ControlUtils.RenewItemsSource(WineOrigins, (await Context.WineOrigins.ToListAsync()).OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId), i => (i as WineOrigin)?.HkId, WineOrigins_SelectionChanged);
if (WineOrigins.SelectedItem == null) {
var hkid = await Context.WbKgs
.GroupBy(k => k.AtKg.Gem.WbGem.HkId)
.Where(g => g.Count() > 0)
.OrderByDescending(g => g.Count())
.Select(g => g.Key)
.FirstOrDefaultAsync();
ControlUtils.SelectListBoxItem(WineOrigins, o => (o as WineOrigin)?.HkId, hkid);
}
ControlUtils.RenewItemsSource(WbGls, await Context.WbGls.OrderBy(g => g.GlNr).ToListAsync(), g => (g as WbGl)?.GlNr, WbGls_SelectionChanged, ControlUtils.RenewSourceDefault.First);
await UpdateWbGems();
await UpdateWbKgs();
await UpdateWbGlKgs();
await UpdateWbRds();
}
private async Task UpdateWbGems() {
WbGemsHeader.Content = "Gemeinden" + (WineOrigins.SelectedItem is WineOrigin o ? $" ({o.Name})" : "");
var selHkId = (WineOrigins.SelectedItem as WineOrigin)?.HkId;
ControlUtils.RenewItemsSource(WbGems, await Context.WbGems.Where(g => g.HkId == selHkId).Select(g => g.AtGem).OrderBy(g => g.Name).ToListAsync(), g => (g as AT_Gem)?.Gkz, WbGems_SelectionChanged);
await UpdateWbKgs();
}
private async Task UpdateWbKgs() {
WbKgsHeader.Content = "Verfügbare KG";
IQueryable<AT_Kg>? kgs = null;
if (WbGems.SelectedItem is AT_Gem g) {
WbKgsHeader.Content += $" ({g.Name})";
kgs = Context.Katastralgemeinden.Where(k => k.Gkz == g.Gkz);
} else if (WineOrigins.SelectedItem is WineOrigin o) {
WbKgsHeader.Content += $" ({o.Name})";
kgs = Context.WbGems.Where(g => g.HkId == o.HkId).SelectMany(g => g.AtGem.Kgs);
} else {
kgs = null;
}
if (kgs == null) {
WbKgs.ItemsSource = null;
} else {
ControlUtils.RenewItemsSource(WbKgs, await kgs.OrderBy(k => k.WbKg.Gl == null).ThenBy(k => k.WbKg.GlNr).ThenBy(k => k.Name).ToListAsync(), k => (k as AT_Kg)?.KgNr, WbKgs_SelectionChanged);
}
}
private async Task UpdateWbGlKgs() {
WbGlKgsHeader.Content = "Aktive KG";
if (WbGls.SelectedItem is WbGl g) {
WbGlKgsHeader.Content += $" ({g.Name})";
ControlUtils.RenewItemsSource(WbGlKgs, await Context.WbKgs.Where(k => k.GlNr == g.GlNr).Select(k => k.AtKg).OrderBy(k => k.Name).ToListAsync(), k => (k as AT_Kg)?.KgNr, WbGlKgs_SelectionChanged);
} else {
WbGlKgs.ItemsSource = null;
}
UpdateButtons();
}
private async Task UpdateWbRds() {
WbRdsHeader.Content = "Riede";
if (WbGlKgs.SelectedItem is AT_Kg k) {
WbRdsHeader.Content += $" ({k.Name})";
ControlUtils.RenewItemsSource(WbRds, await Context.WbRde.Where(r => r.KgNr == k.KgNr).OrderBy(r => r.Name).ToListAsync(), k => (k as AT_Kg)?.KgNr);
} else {
WbRds.ItemsSource = null;
}
UpdateButtons();
}
private async void WineOrigins_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
await UpdateWbGems();
}
private async void WbGls_SelectionChanged(object? sender, SelectionChangedEventArgs? e) {
await UpdateWbGlKgs();
}
private async void WbGems_SelectionChanged(object? sender, SelectionChangedEventArgs? e) {
await UpdateWbKgs();
}
private async void WbGlKgs_SelectionChanged(object sender, SelectionChangedEventArgs e) {
await UpdateWbRds();
if (!isUpdating && WbGlKgs.SelectedItem is AT_Kg k) {
isUpdating = true;
ControlUtils.SelectListBoxItem(WineOrigins, o => (o as WineOrigin)?.HkId, k.Gem.WbGem?.HkId);
ControlUtils.SelectListBoxItem(WbGems, g => (g as AT_Gem)?.Gkz, k.Gkz);
ControlUtils.SelectListBoxItem(WbKgs, k => (k as AT_Kg)?.KgNr, k.KgNr);
isUpdating = false;
}
}
private void WbKgs_SelectionChanged(object sender, SelectionChangedEventArgs e) {
UpdateButtons();
if (!isUpdating && WbKgs.SelectedItem is AT_Kg k && k.WbKg != null && ((WbGls.SelectedItem as WbGl)?.GlNr == k.WbKg?.GlNr || WbGls.SelectedItem == null)) {
isUpdating = true;
ControlUtils.SelectListBoxItem(WbGls, g => (g as WbGl)?.GlNr, k.WbKg?.GlNr);
ControlUtils.SelectListBoxItem(WbGlKgs, k => (k as AT_Kg)?.KgNr, k.KgNr);
isUpdating = false;
}
}
private void UpdateButtons() {
if (WbKgs.SelectedItem is AT_Kg v) {
ActivateKgButton.IsEnabled = v.WbKg?.GlNr != (WbGls.SelectedItem as WbGl)?.GlNr;
ActivateKgButton.ToolTip = $"KG {v.Name} Großlage {(WbGls.SelectedItem as WbGl)?.Name} zuweisen";
} else {
ActivateKgButton.IsEnabled = false;
ActivateKgButton.ToolTip = $"Verfügbare Katastralgemeinde Großlage {(WbGls.SelectedItem as WbGl)?.Name} zuweisen";
}
if (WbGlKgs.SelectedItem is AT_Kg a) {
DeactivateKgButton.IsEnabled = true;
DeactivateKgButton.ToolTip = $"KG {a.Name} deaktivieren";
} else {
DeactivateKgButton.IsEnabled = false;
DeactivateKgButton.ToolTip = "Aktive Katastralgemeinde deaktivieren";
}
}
private async void ActivateKgButton_Click(object sender, RoutedEventArgs e) {
if (WbKgs.SelectedItem is not AT_Kg k || WbGls.SelectedItem is not WbGl g) return;
try {
if (k.WbKg != null) {
k.WbKg.GlNr = g.GlNr;
Context.Update(k.WbKg);
} else {
var wbKg = Context.CreateProxy<WbKg>();
wbKg.KgNr = k.KgNr;
wbKg.GlNr = g.GlNr;
await Context.AddAsync(wbKg);
}
await Context.SaveChangesAsync();
await App.HintContextChange();
ControlUtils.SelectListBoxItem(WbGlKgs, kg => (kg as AT_Kg)?.KgNr, k.KgNr);
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Katastralgemeinde aktivieren", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private async void DeactivateKgButton_Click(object sender, RoutedEventArgs e) {
if (WbGlKgs.SelectedItem is not AT_Kg k || k.WbKg == null) return;
try {
Context.Remove(k.WbKg);
await Context.SaveChangesAsync();
await App.HintContextChange();
ControlUtils.SelectListBoxItem(WbKgs, kg => (kg as AT_Kg)?.KgNr, k.KgNr);
} catch (Exception exc) {
await HintContextChange();
var str = "Der Eintrag konnte nicht aus der Datenbank gelöscht werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Katastralgemeinde deaktivieren", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public void FocusKgNr(int kgnr) {
var kg = Context.Katastralgemeinden.Find(kgnr);
ControlUtils.SelectListBoxItem(WbGls, kg.WbKg.Gl, g => (g as WbGl)?.GlNr);
ControlUtils.SelectListBoxItem(WbGlKgs, kg, k => (k as AT_Kg)?.KgNr);
WbGlKgs.Focus();
}
}
}