using C4IT.FASD.Base; using FasdDesktopUi.Basics; using FasdDesktopUi.Basics.Models; using System; using System.ComponentModel; using System.Linq; using System.Reflection; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; using WinForms = System.Windows.Forms; using static C4IT.Logging.cLogManager; namespace FasdDesktopUi.Pages.TicketCompletion { public partial class TicketCompletion : Window, IBlurInvoker, INotifyPropertyChanged { private const double MinWindowHeightDip = 220d; private const double WindowWorkingAreaMarginDip = 12d; private const double DialogNonContentReserveDip = 180d; private bool isUpdatingDialogBounds; private bool isCanceled = false; private bool _WaitForClosing = false; public bool WaitForClosing { get { return _WaitForClosing; } set { if (value != _WaitForClosing) { _WaitForClosing = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("WaitForClosing")); } } } private readonly cSupportCaseDataProvider _dataProvider; public event PropertyChangedEventHandler PropertyChanged; private TicketCompletion(cSupportCaseDataProvider dataProvider) { InitializeComponent(); _dataProvider = dataProvider; CloseCaseDialogUc.DataProvider = _dataProvider; } protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); cFocusInvoker.GotFocus += ElementGotFocus; cFocusInvoker.LostFocus += ElementLostFocus; SizeChanged += TicketCompletion_SizeChanged; Loaded += TicketCompletion_Loaded; } protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); UpdateDialogMaxHeightToScreen(); } protected override void OnLocationChanged(EventArgs e) { base.OnLocationChanged(e); UpdateDialogMaxHeightToScreen(); } private void TicketCompletion_Loaded(object sender, RoutedEventArgs e) => UpdateDialogMaxHeightToScreen(); private void TicketCompletion_SizeChanged(object sender, SizeChangedEventArgs e) => UpdateDialogMaxHeightToScreen(); #region ClosingBusy public bool IsClosingBusy { get { return (bool)GetValue(IsClosingBusyProperty); } set { SetValue(IsClosingBusyProperty, value); } } public static readonly DependencyProperty IsClosingBusyProperty = DependencyProperty.Register("IsClosingBusy", typeof(bool), typeof(TicketCompletion), new PropertyMetadata(false)); #endregion public static bool? Show(cSupportCaseDataProvider DataProvider, Window Owner) { try { var existingMessageBox = Application.Current.Windows.Cast().FirstOrDefault(window => window is TicketCompletion); if (existingMessageBox != null) { existingMessageBox.Show(); return null; } TicketCompletion ticketCompletion = new TicketCompletion(DataProvider); if (Owner != null) ticketCompletion.Owner = Owner; else ticketCompletion.WindowStartupLocation = WindowStartupLocation.CenterScreen; bool? dialogResult = null; try { dialogResult = ticketCompletion.ShowDialog(); } catch (Exception E) { LogException(E); } return ticketCompletion.isCanceled ? null : dialogResult; } catch (Exception E) { LogException(E); } return null; } #region Close_Click private void Close_Click() { isCanceled = true; TrySetDialogResult(null); Close(); } private void CloseButton_Click(object sender, InputEventArgs e) => Close_Click(); #endregion private void TrySetDialogResult(bool? result) { try { DialogResult = result; } catch (InvalidOperationException) { // Window was not shown as dialog; ignore. } } private void UpdateDialogMaxHeightToScreen() { if (isUpdatingDialogBounds) return; isUpdatingDialogBounds = true; try { WinForms.Screen screen = null; IntPtr currentHandle = new WindowInteropHelper(this).Handle; if (currentHandle != IntPtr.Zero) { screen = WinForms.Screen.FromHandle(currentHandle); } else if (Owner != null) { IntPtr ownerHandle = new WindowInteropHelper(Owner).Handle; if (ownerHandle != IntPtr.Zero) screen = WinForms.Screen.FromHandle(ownerHandle); } screen = screen ?? WinForms.Screen.PrimaryScreen; var workingArea = screen?.WorkingArea ?? WinForms.Screen.PrimaryScreen.WorkingArea; var dpiScaleY = VisualTreeHelper.GetDpi(this).DpiScaleY; var safeDpiScaleY = Math.Max(0.1, dpiScaleY); var workingAreaTopDip = workingArea.Top / safeDpiScaleY; var workingAreaBottomDip = workingArea.Bottom / safeDpiScaleY; var workingAreaHeightDip = workingArea.Height / safeDpiScaleY; var availableWindowHeightDip = workingAreaHeightDip - (WindowWorkingAreaMarginDip * 2); MaxHeight = Math.Max(MinWindowHeightDip, availableWindowHeightDip); if (!double.IsNaN(Top)) { var minTop = workingAreaTopDip + WindowWorkingAreaMarginDip; var maxBottom = workingAreaBottomDip - WindowWorkingAreaMarginDip; if (Top < minTop) Top = minTop; var currentBottom = Top + ActualHeight; if (currentBottom > maxBottom) Top = Math.Max(minTop, maxBottom - ActualHeight); } double nonDialogReserve = DialogNonContentReserveDip; if (CloseCaseDialogUc != null && CloseCaseDialogUc.IsLoaded) { var estimatedReserve = ActualHeight - CloseCaseDialogUc.ActualHeight; if (estimatedReserve > 0) nonDialogReserve = Math.Max(nonDialogReserve, estimatedReserve + WindowWorkingAreaMarginDip); } CloseCaseDialogUc?.SetDialogContentMaxHeight(MaxHeight - nonDialogReserve); } catch (Exception ex) { LogException(ex); } finally { isUpdatingDialogBounds = false; } } #region Internal Focus Events private void ElementGotFocus(object sender, EventArgs e) { try { FocusBorder.Visibility = Visibility.Visible; if (!(sender is FrameworkElement senderElement)) return; if (FocusBorder.IsVisible is false) return; var desiredHeight = senderElement.ActualHeight; var desiredWidth = senderElement.ActualWidth; FrameworkElement placeHolderElement = new FrameworkElement() { Height = desiredHeight, Width = desiredWidth, Margin = senderElement.Margin }; FocusDecorator.Height = desiredHeight + senderElement.Margin.Top + senderElement.Margin.Bottom; FocusDecorator.Width = desiredWidth + senderElement.Margin.Left + senderElement.Margin.Right; Point relativePoint = senderElement.TransformToAncestor(this) .Transform(new Point(0, 0)); if (senderElement.Parent is Decorator actualParentDecorator) actualParentDecorator.Child = placeHolderElement; else if (senderElement.Parent is Panel actualParentPanel) { if (actualParentPanel is Grid) { Grid.SetColumn(placeHolderElement, Grid.GetColumn(senderElement)); Grid.SetRow(placeHolderElement, Grid.GetRow(senderElement)); } actualParentPanel.Children.Insert(actualParentPanel.Children.IndexOf(senderElement), placeHolderElement); actualParentPanel.Children.Remove(senderElement); } Canvas.SetLeft(FocusDecorator, relativePoint.X - (senderElement.Margin.Left)); Canvas.SetTop(FocusDecorator, relativePoint.Y - senderElement.Margin.Top); FocusDecorator.Child = senderElement; } catch (Exception E) { LogException(E); } } private void ElementLostFocus(object sender, EventArgs e) { try { FocusBorder.Visibility = Visibility.Collapsed; } catch (Exception E) { LogException(E); } } #endregion private void CustomMessageBox_PreviewKeyDown(object sender, KeyEventArgs e) { switch (e.Key) { case Key.Escape: Close_Click(); break; } } private async Task DoCloseActionAsync() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { WaitForClosing = true; SafeText.IsEnabled = false; AbortText.IsEnabled = false; IsClosingBusy = true; bool closedSuccessfull = await CloseCaseDialogUc.CloseCaseAsync(_dataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.User).Id); if (closedSuccessfull) { SuccessPage.SuccessPage successPage = new SuccessPage.SuccessPage(); successPage.Show(); await _dataProvider?.CloseCaseAsync(); TrySetDialogResult(true); Close(); } } catch (Exception E) { LogException(E); } finally { WaitForClosing = false; SafeText.IsEnabled = true; AbortText.IsEnabled = true; LogMethodEnd(CM); } } public void BlurInvoker_IsActiveChanged(object sender, DependencyPropertyChangedEventArgs e) { BlurInvoker.InvokeVisibilityChanged(this, new EventArgs()); } public bool BlurInvoker_IsActive => IsVisible; public void SetButtonStateYes(bool Enabled, string MouseOverMessage) { var _h = this.Dispatcher.BeginInvoke(new Action(() => { try { ToolTip tip = null; if (!string.IsNullOrEmpty(MouseOverMessage)) tip = new ToolTip { Content = MouseOverMessage }; SafeText.IsEnabled = Enabled; GridPanel.ToolTip = tip; } catch (Exception E) { LogException(E); } })); } public void SetButtonStateNo(bool Enabled, string MouseOverMessage) { _ = this.Dispatcher.BeginInvoke(new Action(() => { try { ToolTip tip = null; if (!string.IsNullOrEmpty(MouseOverMessage)) tip = new ToolTip { Content = MouseOverMessage }; AbortText.IsEnabled = Enabled; AbortText.ToolTip = tip; } catch (Exception E) { LogException(E); } })); } private async void SafeText_Click(object sender, InputEventArgs e) => await DoCloseActionAsync(); private void AbortText_Click(object sender, InputEventArgs e) => Close_Click(); } }