Files
C4IT-F4SD-Client/FasdDesktopUi/Basics/UserControls/ComboBoxPageable.xaml.cs
2026-02-09 19:55:29 +01:00

433 lines
14 KiB
C#

using C4IT.FASD.Base;
using C4IT.MultiLanguage;
using FasdDesktopUi.Basics.Helper;
using FasdDesktopUi.Basics.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Navigation;
using static C4IT.Logging.cLogManager;
namespace FasdDesktopUi.Basics.UserControls
{
public partial class ComboBoxPageable : UserControl, IFocusInvoker
{
#region Fields & Properties
private const int itemsPerPage = 10;
private const double searchDelayInMilliseconds = 350;
private int pageIndex = 0;
private int pageCount = 1;
private readonly Timer timer = new Timer(searchDelayInMilliseconds);
private readonly cF4sdHealthSelectionDataRequest searchData = new cF4sdHealthSelectionDataRequest() { Search = string.Empty, Page = 0, PageSize = itemsPerPage };
public int? ParentIndex { get; set; }
public UIElement ParentElement { get; set; }
public string ResetFilterLabel
{
get { return (string)GetValue(ResetFilterLabelProperty); }
set { SetValue(ResetFilterLabelProperty, value); }
}
public static readonly DependencyProperty ResetFilterLabelProperty =
DependencyProperty.Register("ResetFilterLabel", typeof(string), typeof(ComboBoxPageable), new PropertyMetadata(cMultiLanguageSupport.GetItem("Dialog.CloseCase.ResetFilter")));
public bool ResetFilter
{
get { return (bool)GetValue(ResetFilterProperty); }
set { SetValue(ResetFilterProperty, value); }
}
public static readonly DependencyProperty ResetFilterProperty =
DependencyProperty.Register("ResetFilter", typeof(bool), typeof(ComboBoxPageable), new PropertyMetadata(false, new PropertyChangedCallback(ResetFilterChanged)));
private static void ResetFilterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
try
{
if (!(d is ComboBoxPageable me))
return;
me.searchData.ResetFilter = me.ResetFilter;
me.InvokeSearchValueChanged();
}
catch (Exception E)
{
LogException(E);
}
}
#region TotalItemCount
public int TotalItemCount
{
get { return (int)GetValue(TotalItemCountProperty); }
set { SetValue(TotalItemCountProperty, value); }
}
public static readonly DependencyProperty TotalItemCountProperty =
DependencyProperty.Register("TotalItemCount", typeof(int), typeof(ComboBoxPageable), new PropertyMetadata(0, new PropertyChangedCallback(TotalItemCountChanged)));
private static void TotalItemCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
try
{
if (!(d is ComboBoxPageable me))
return;
me.pageCount = me.TotalItemCount % itemsPerPage == 0 ? me.TotalItemCount / itemsPerPage : (me.TotalItemCount / itemsPerPage) + 1;
me.UpdatePageTracker();
}
catch (Exception E)
{
LogException(E);
}
}
#endregion
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(
"SelectedItem",
typeof(object),
typeof(ComboBoxPageable),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
#region SearchDataChanged
public EventHandler<cF4sdHealthSelectionDataRequest> SearchDataChanged
{
get { return (EventHandler<cF4sdHealthSelectionDataRequest>)GetValue(SearchDataChangedProperty); }
set { SetValue(SearchDataChangedProperty, value); }
}
public static readonly DependencyProperty SearchDataChangedProperty =
DependencyProperty.Register("SearchDataChanged", typeof(EventHandler<cF4sdHealthSelectionDataRequest>), typeof(ComboBoxPageable), new PropertyMetadata(null));
#endregion
#region RestoreParentScrollFocusOnDropDownClose
public bool RestoreParentScrollFocusOnDropDownClose
{
get { return (bool)GetValue(RestoreParentScrollFocusOnDropDownCloseProperty); }
set { SetValue(RestoreParentScrollFocusOnDropDownCloseProperty, value); }
}
public static readonly DependencyProperty RestoreParentScrollFocusOnDropDownCloseProperty =
DependencyProperty.Register("RestoreParentScrollFocusOnDropDownClose", typeof(bool), typeof(ComboBoxPageable), new PropertyMetadata(false));
#endregion
#region ItemData
public ObservableCollection<KeyValuePair<string, object>> ItemData
{
get { return (ObservableCollection<KeyValuePair<string, object>>)GetValue(ItemDataProperty); }
set
{
SetValue(ItemDataProperty, value);
}
}
public static readonly DependencyProperty ItemDataProperty =
DependencyProperty.Register("ItemData", typeof(ObservableCollection<KeyValuePair<string, object>>), typeof(ComboBoxPageable), new PropertyMetadata(null));
#endregion
#region Styles
public Brush ComboBoxBackground
{
get { return (Brush)GetValue(ComboBoxBackgroundProperty); }
set { SetValue(ComboBoxBackgroundProperty, value); }
}
public static readonly DependencyProperty ComboBoxBackgroundProperty =
DependencyProperty.Register("ComboBoxBackground", typeof(Brush), typeof(ComboBoxPageable), new PropertyMetadata(Brushes.Transparent));
#endregion
#endregion
public ComboBoxPageable()
{
InitializeComponent();
timer.Elapsed += TimerElapsed;
}
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
try
{
timer.Stop();
Dispatcher.Invoke(InvokeSearchValueChanged);
}
catch (Exception E)
{
LogException(E);
}
}
private void InvokeSearchValueChanged()
{
try
{
searchData.Page = pageIndex;
if (SearchDataChanged != null)
SearchDataChanged.Invoke(this, searchData);
}
catch (Exception E)
{
LogException(E);
}
}
public KeyValuePair<string, object>? GetSelectedValue()
{
try
{
if (ComboBoxControl.SelectedItem is KeyValuePair<string, object> selectedItem)
return selectedItem;
}
catch (Exception E)
{
LogException(E);
}
return null;
}
#region Paging Events
#region PageBack
private void PageBackButton_Click(RoutedEventArgs e)
{
if (pageIndex <= 0)
{
e.Handled = true;
return;
}
pageIndex--;
InvokeSearchValueChanged();
UpdatePageTracker();
e.Handled = true;
}
private void PageBackButton_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
PageBackButton_Click(e);
}
private void PageBackButton_TouchDown(object sender, TouchEventArgs e)
{
PageBackButton_Click(e);
}
#endregion
#region PageFor
private void PageForButton_Click(RoutedEventArgs e)
{
if (pageIndex + 1 >= pageCount)
return;
pageIndex++;
InvokeSearchValueChanged();
UpdatePageTracker();
e.Handled = true;
}
private void PageForButton_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
PageForButton_Click(e);
}
private void PageForButton_TouchDown(object sender, TouchEventArgs e)
{
PageForButton_Click(e);
}
#endregion
#endregion
private void UpdatePageTracker()
{
try
{
var pageTrackerElement = ComboBoxControl.Template.FindName("PageTrackerTextBlock", ComboBoxControl);
if (!(pageTrackerElement is TextBlock pageTrackerTextBlock))
return;
pageTrackerTextBlock.Text = $"{pageIndex + 1} / {pageCount}";
}
catch (Exception E)
{
LogException(E);
}
}
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
try
{
if (!(sender is TextBox searchTextBox))
return;
pageIndex = 0;
searchData.Search = searchTextBox.Text;
UpdatePageTracker();
timer.Stop();
timer.Start();
}
catch (Exception E)
{
LogException(E);
}
}
private void ComboBoxControl_DropDownClosed(object sender, EventArgs e)
{
timer.Stop();
cFocusInvoker.InvokeLostFocus(this, e);
if (RestoreParentScrollFocusOnDropDownClose)
{
_ = Dispatcher.BeginInvoke((Action)(() =>
{
try
{
var parentScrollViewer = cUiElementHelper.GetFirstParentOfType<ScrollViewer>(this);
Keyboard.ClearFocus();
if (parentScrollViewer != null)
{
parentScrollViewer.Focus();
Keyboard.Focus(parentScrollViewer);
}
}
catch (Exception exception)
{
LogException(exception);
}
}), System.Windows.Threading.DispatcherPriority.Input);
}
}
private void ComboBoxControl_DropDownOpened(object sender, EventArgs e)
{
try
{
// Elterninfo nur setzen, wenn (noch) nicht sinnvoll vorhanden
bool invalidIndex = false;
if (ParentElement is Panel p && (ParentIndex == null || ParentIndex < 0 || ParentIndex > p.Children.Count))
invalidIndex = true;
if (ParentElement == null || invalidIndex)
{
ParentElement = this.Parent as UIElement;
if (this.Parent is Panel panel)
ParentIndex = panel.Children.IndexOf(this);
else
ParentIndex = null;
}
cFocusInvoker.InvokeGotFocus(this, e);
InvokeSearchValueChanged();
#region Focus auf Textfeld setzen beim Öffnen der Combobox
if (!(sender is ComboBox comboBox)) return;
// Zugriff auf das Popup-Element
Popup partPopup = comboBox.Template.FindName("PART_Popup", comboBox) as Popup;
if (partPopup == null) return;
// Verzögerter Fokus
var _h = Dispatcher.BeginInvoke((Action)(() =>
{
if (partPopup.IsOpen)
{
// Suchen des SearchTextBox-Element innerhalb des Popups
TextBox searchTextBox = FindVisualChild<TextBox>(partPopup.Child, "SearchTextBox");
if (searchTextBox != null)
{
// Setzen des Fokus auf TextBox
searchTextBox.Focus();
}
}
}), System.Windows.Threading.DispatcherPriority.Loaded);
#endregion
}
catch (Exception E)
{
LogException(E);
}
}
private static T FindVisualChild<T>(DependencyObject parent, string childName) where T : DependencyObject
{
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
var childType = child as T;
if (childType == null)
{
foundChild = FindVisualChild<T>(child, childName);
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
if (frameworkElement != null && frameworkElement.Name == childName)
{
return (T)child;
}
}
else
{
return (T)child;
}
}
return foundChild;
}
}
}