inital
This commit is contained in:
362
FasdDesktopUi/Basics/UserControls/TicketOverview.xaml.cs
Normal file
362
FasdDesktopUi/Basics/UserControls/TicketOverview.xaml.cs
Normal file
@@ -0,0 +1,362 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
|
||||
using C4IT.FASD.Cockpit.Communication;
|
||||
using FasdDesktopUi.Basics.Models;
|
||||
using FasdDesktopUi.Basics.Services.Models;
|
||||
using FasdDesktopUi.Pages.SearchPage;
|
||||
namespace FasdDesktopUi.Basics.UserControls
|
||||
{
|
||||
public partial class TicketOverview : UserControl
|
||||
{
|
||||
private readonly TicketOverviewModel _viewModel = new TicketOverviewModel();
|
||||
private bool _isInitialized;
|
||||
private static readonly (string Key, Action<TicketOverviewModel, int> Setter)[] CategorySetters = new[]
|
||||
{
|
||||
("TicketsNew", new Action<TicketOverviewModel, int>((vm, value) => { vm.TicketsNew = value; })),
|
||||
("TicketsActive", new Action<TicketOverviewModel, int>((vm, value) => { vm.TicketsActive = value; })),
|
||||
("TicketsCritical", new Action<TicketOverviewModel, int>((vm, value) => { vm.TicketsCritical = value; })),
|
||||
("TicketsNewInfo", new Action<TicketOverviewModel, int>((vm, value) => { vm.TicketsNewInfo = value; })),
|
||||
("IncidentNew", new Action<TicketOverviewModel, int>((vm, value) => { vm.IncidentNew = value; })),
|
||||
("IncidentActive", new Action<TicketOverviewModel, int>((vm, value) => { vm.IncidentActive = value; })),
|
||||
("IncidentCritical", new Action<TicketOverviewModel, int>((vm, value) => { vm.IncidentCritical = value; })),
|
||||
("IncidentNewInfo", new Action<TicketOverviewModel, int>((vm, value) => { vm.IncidentNewInfo = value; })),
|
||||
("UnassignedTickets", new Action<TicketOverviewModel, int>((vm, value) => { vm.UnassignedTickets = value; })),
|
||||
("UnassignedTicketsCritical", new Action<TicketOverviewModel, int>((vm, value) => { vm.UnassignedTicketsCritical = value; }))
|
||||
};
|
||||
private static readonly (string Key, Action<TicketOverviewModel, bool> Setter)[] HighlightSetters = new[]
|
||||
{
|
||||
("TicketsNew", new Action<TicketOverviewModel, bool>((vm, value) => { vm.TicketsNewHighlighted = value; })),
|
||||
("TicketsActive", new Action<TicketOverviewModel, bool>((vm, value) => { vm.TicketsActiveHighlighted = value; })),
|
||||
("TicketsCritical", new Action<TicketOverviewModel, bool>((vm, value) => { vm.TicketsCriticalHighlighted = value; })),
|
||||
("TicketsNewInfo", new Action<TicketOverviewModel, bool>((vm, value) => { vm.TicketsNewInfoHighlighted = value; })),
|
||||
("IncidentNew", new Action<TicketOverviewModel, bool>((vm, value) => { vm.IncidentNewHighlighted = value; })),
|
||||
("IncidentActive", new Action<TicketOverviewModel, bool>((vm, value) => { vm.IncidentActiveHighlighted = value; })),
|
||||
("IncidentCritical", new Action<TicketOverviewModel, bool>((vm, value) => { vm.IncidentCriticalHighlighted = value; })),
|
||||
("IncidentNewInfo", new Action<TicketOverviewModel, bool>((vm, value) => { vm.IncidentNewInfoHighlighted = value; })),
|
||||
("UnassignedTickets", new Action<TicketOverviewModel, bool>((vm, value) => { vm.UnassignedTicketsHighlighted = value; })),
|
||||
("UnassignedTicketsCritical", new Action<TicketOverviewModel, bool>((vm, value) => { vm.UnassignedTicketsCriticalHighlighted = value; }))
|
||||
};
|
||||
private static readonly (string Key, Action<TicketOverviewModel, string> Setter)[] ChangeHintSetters = new[]
|
||||
{
|
||||
("TicketsNew", new Action<TicketOverviewModel, string>((vm, value) => { vm.TicketsNewChangeHint = value; })),
|
||||
("TicketsActive", new Action<TicketOverviewModel, string>((vm, value) => { vm.TicketsActiveChangeHint = value; })),
|
||||
("TicketsCritical", new Action<TicketOverviewModel, string>((vm, value) => { vm.TicketsCriticalChangeHint = value; })),
|
||||
("TicketsNewInfo", new Action<TicketOverviewModel, string>((vm, value) => { vm.TicketsNewInfoChangeHint = value; })),
|
||||
("IncidentNew", new Action<TicketOverviewModel, string>((vm, value) => { vm.IncidentNewChangeHint = value; })),
|
||||
("IncidentActive", new Action<TicketOverviewModel, string>((vm, value) => { vm.IncidentActiveChangeHint = value; })),
|
||||
("IncidentCritical", new Action<TicketOverviewModel, string>((vm, value) => { vm.IncidentCriticalChangeHint = value; })),
|
||||
("IncidentNewInfo", new Action<TicketOverviewModel, string>((vm, value) => { vm.IncidentNewInfoChangeHint = value; })),
|
||||
("UnassignedTickets", new Action<TicketOverviewModel, string>((vm, value) => { vm.UnassignedTicketsChangeHint = value; })),
|
||||
("UnassignedTicketsCritical", new Action<TicketOverviewModel, string>((vm, value) => { vm.UnassignedTicketsCriticalChangeHint = value; }))
|
||||
};
|
||||
private readonly Dictionary<string, HighlightInfo> _personalHighlightStates = new Dictionary<string, HighlightInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly Dictionary<string, HighlightInfo> _roleHighlightStates = new Dictionary<string, HighlightInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
#region Properties
|
||||
public static TicketOverview Instance { get; private set; }
|
||||
|
||||
public static readonly DependencyProperty IsSelectedProperty =
|
||||
DependencyProperty.RegisterAttached(
|
||||
"IsSelected",
|
||||
typeof(bool),
|
||||
typeof(TicketOverview),
|
||||
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
||||
|
||||
public static void SetIsSelected(UIElement element, bool value) =>
|
||||
element.SetValue(IsSelectedProperty, value);
|
||||
|
||||
public static bool GetIsSelected(UIElement element) =>
|
||||
(bool)element.GetValue(IsSelectedProperty);
|
||||
|
||||
public static readonly DependencyProperty IsHighlightedProperty =
|
||||
DependencyProperty.RegisterAttached(
|
||||
"IsHighlighted",
|
||||
typeof(bool),
|
||||
typeof(TicketOverview),
|
||||
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
||||
|
||||
public static void SetIsHighlighted(UIElement element, bool value) =>
|
||||
element.SetValue(IsHighlightedProperty, value);
|
||||
|
||||
public static bool GetIsHighlighted(UIElement element) =>
|
||||
(bool)element.GetValue(IsHighlightedProperty);
|
||||
#endregion
|
||||
|
||||
public delegate void TicketOverviewSelectionRequestedEventHandler(object sender, TicketOverviewSelectionRequestedEventArgs e);
|
||||
|
||||
public static readonly RoutedEvent SelectionRequestedEvent =
|
||||
EventManager.RegisterRoutedEvent(
|
||||
"SelectionRequested",
|
||||
RoutingStrategy.Bubble,
|
||||
typeof(TicketOverviewSelectionRequestedEventHandler),
|
||||
typeof(TicketOverview));
|
||||
|
||||
public event TicketOverviewSelectionRequestedEventHandler SelectionRequested
|
||||
{
|
||||
add { AddHandler(SelectionRequestedEvent, value); }
|
||||
remove { RemoveHandler(SelectionRequestedEvent, value); }
|
||||
}
|
||||
|
||||
#region Initial
|
||||
public TicketOverview()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = _viewModel;
|
||||
Loaded += TicketOverview_Loaded;
|
||||
Instance = this;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Click-Events
|
||||
private void Label_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (!(sender is Label lbl) || !(lbl.Tag is string propName) || !(DataContext is TicketOverviewModel vm))
|
||||
return;
|
||||
|
||||
var vmType = vm.GetType();
|
||||
var boolProp = vmType.GetProperty(propName);
|
||||
if (boolProp?.PropertyType != typeof(bool))
|
||||
return;
|
||||
|
||||
var wasSelected = (bool)(boolProp.GetValue(vm) ?? false);
|
||||
|
||||
var keyBase = propName.EndsWith("Selected", StringComparison.Ordinal)
|
||||
? propName.Substring(0, propName.Length - "Selected".Length)
|
||||
: propName;
|
||||
|
||||
int count = 0;
|
||||
var countProp = vmType.GetProperty(keyBase) ?? vmType.GetProperty(keyBase + "Count");
|
||||
if (countProp?.PropertyType == typeof(int))
|
||||
count = (int)(countProp.GetValue(vm) ?? 0);
|
||||
|
||||
if (count <= 0)
|
||||
{
|
||||
boolProp.SetValue(vm, false);
|
||||
ClearHighlight(keyBase, SearchPageView.Instance?.IsFilterChecked == true);
|
||||
SearchPageView.Instance?.CloseTicketOverviewResults();
|
||||
return;
|
||||
}
|
||||
|
||||
if (wasSelected)
|
||||
{
|
||||
boolProp.SetValue(vm, false);
|
||||
ClearHighlight(keyBase, SearchPageView.Instance?.IsFilterChecked == true);
|
||||
SearchPageView.Instance?.CloseTicketOverviewResults();
|
||||
return;
|
||||
}
|
||||
|
||||
vm.ResetSelection(); // setzt alle ...Selected auf false
|
||||
boolProp.SetValue(vm, true);
|
||||
|
||||
bool useRoleScope = false;
|
||||
try { useRoleScope = SearchPageView.Instance?.IsFilterChecked == true; } catch { }
|
||||
|
||||
ClearHighlight(keyBase, useRoleScope);
|
||||
|
||||
var args = new TicketOverviewSelectionRequestedEventArgs(
|
||||
SelectionRequestedEvent,
|
||||
this,
|
||||
keyBase,
|
||||
useRoleScope,
|
||||
count
|
||||
);
|
||||
RaiseEvent(args);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
private async void TicketOverview_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_isInitialized)
|
||||
return;
|
||||
|
||||
_isInitialized = true;
|
||||
|
||||
bool filter = SearchPageView.Instance?.IsFilterChecked == true;
|
||||
await UpdateDataContextAsync(filter);
|
||||
|
||||
if (SearchPageView.Instance != null)
|
||||
{
|
||||
SearchPageView.Instance.FilterToggleCheckedChanged += async (s, isChecked) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await UpdateDataContextAsync(isChecked);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[TicketOverview] Refresh after toggle failed: {ex}");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetSelection()
|
||||
{
|
||||
if (DataContext is TicketOverviewModel vm)
|
||||
vm.ResetSelection();
|
||||
}
|
||||
/// <summary>
|
||||
/// Prüft welche Daten für die Ansicht geladen werden sollen
|
||||
/// Wenn UseRoledTickets = true dann Rolebased Tickets und Incidents laden
|
||||
/// Wenn UseRoledTickets = false dann meine Eigenen Tickets und Incidents laden
|
||||
/// </summary>
|
||||
/// <param name="useRoleTickets"></param>
|
||||
private Task UpdateDataContextAsync(bool useRoleTickets)
|
||||
{
|
||||
return RefreshCountsAsync(useRoleTickets);
|
||||
}
|
||||
|
||||
private async Task RefreshCountsAsync(bool useRoleTickets)
|
||||
{
|
||||
var communication = cFasdCockpitCommunicationBase.Instance;
|
||||
|
||||
var counts = CategorySetters.ToDictionary(item => item.Key, _ => 0);
|
||||
|
||||
if (communication != null)
|
||||
{
|
||||
var tasks = CategorySetters.ToDictionary(
|
||||
item => item.Key,
|
||||
item => communication.GetTicketOverviewRelations(item.Key, useRoleTickets, 0));
|
||||
|
||||
foreach (var kvp in tasks)
|
||||
{
|
||||
try
|
||||
{
|
||||
var relations = await kvp.Value.ConfigureAwait(false);
|
||||
counts[kvp.Key] = relations?.Count ?? 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[TicketOverview] Failed to load count for '{kvp.Key}': {ex}");
|
||||
counts[kvp.Key] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
foreach (var (key, setter) in CategorySetters)
|
||||
{
|
||||
setter(_viewModel, counts[key]);
|
||||
}
|
||||
|
||||
_viewModel.ResetSelection();
|
||||
SearchPageView.Instance?.CloseTicketOverviewResults();
|
||||
UpdateHighlightState(useRoleTickets);
|
||||
}, DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
public void UpdateCounts(IDictionary<string, int> counts, bool useRoleTickets)
|
||||
{
|
||||
if (counts == null)
|
||||
return;
|
||||
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
foreach (var (key, setter) in CategorySetters)
|
||||
{
|
||||
counts.TryGetValue(key, out var value);
|
||||
setter(_viewModel, value);
|
||||
}
|
||||
|
||||
UpdateHighlightState(useRoleTickets);
|
||||
}, DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
public void SetHighlights(IEnumerable<TileCountChange> changes, bool useRoleTickets)
|
||||
{
|
||||
if (changes != null)
|
||||
{
|
||||
foreach (var change in changes)
|
||||
{
|
||||
if (change.Delta <= 0)
|
||||
continue;
|
||||
|
||||
var target = change.Scope == TileScope.Personal ? _personalHighlightStates : _roleHighlightStates;
|
||||
|
||||
if (!target.TryGetValue(change.Key, out var info))
|
||||
{
|
||||
info = new HighlightInfo(change.OldCount);
|
||||
target[change.Key] = info;
|
||||
}
|
||||
|
||||
info.Current = change.NewCount;
|
||||
|
||||
if (info.Current == info.Baseline)
|
||||
target.Remove(change.Key);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateHighlightState(useRoleTickets);
|
||||
}
|
||||
|
||||
public void RefreshHighlightState(bool useRoleTickets)
|
||||
{
|
||||
UpdateHighlightState(useRoleTickets);
|
||||
}
|
||||
|
||||
private void UpdateHighlightState(bool useRoleTickets)
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
var highlightStates = useRoleTickets ? _roleHighlightStates : _personalHighlightStates;
|
||||
|
||||
foreach (var (key, setter) in HighlightSetters)
|
||||
{
|
||||
setter(_viewModel, highlightStates.ContainsKey(key));
|
||||
}
|
||||
|
||||
foreach (var (key, setter) in ChangeHintSetters)
|
||||
{
|
||||
if (highlightStates.TryGetValue(key, out var info))
|
||||
setter(_viewModel, FormatDelta(info.Current - info.Baseline));
|
||||
else
|
||||
setter(_viewModel, null);
|
||||
}
|
||||
}, DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
private void ClearHighlight(string key, bool useRoleScope)
|
||||
{
|
||||
var highlightStates = useRoleScope ? _roleHighlightStates : _personalHighlightStates;
|
||||
if (!highlightStates.Remove(key))
|
||||
return;
|
||||
|
||||
UpdateHighlightState(useRoleScope);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
private static string FormatDelta(int delta)
|
||||
{
|
||||
if (delta == 0)
|
||||
return null;
|
||||
|
||||
var prefix = delta > 0 ? "+" : string.Empty;
|
||||
return prefix + delta.ToString();
|
||||
}
|
||||
|
||||
private sealed class HighlightInfo
|
||||
{
|
||||
public HighlightInfo(int baseline)
|
||||
{
|
||||
Baseline = baseline;
|
||||
Current = baseline;
|
||||
}
|
||||
|
||||
public int Baseline { get; }
|
||||
|
||||
public int Current { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user