aktueller Stand

This commit is contained in:
Meik
2026-02-03 16:46:49 +01:00
parent 7192319e1e
commit 696629b5a8
5 changed files with 431 additions and 284 deletions

View File

@@ -39,8 +39,12 @@ namespace FasdDesktopUi
public System.Windows.Forms.NotifyIcon notifyIcon = new System.Windows.Forms.NotifyIcon() { Text = $"First Aid Service Desk" };
public bool UseOsLanguage = string.IsNullOrEmpty(cFasdCockpitConfig.Instance.SelectedLanguage);
#region Ticketübersicht
private TrayTicketNotificationManager _ticketTrayNotification;
private TileScope? _pendingTicketOverviewScope;
#endregion
private async void Application_Startup(object sender, StartupEventArgs e)
{
@@ -181,18 +185,8 @@ namespace FasdDesktopUi
if (searchView == null)
return;
var hasNotification = HasPendingTicketOverviewNotification();
if (hasNotification)
{
if (!searchView.IsVisible)
searchView.ActivateSearchView();
else
searchView.BringToFrontPreserveState();
searchView.ShowTicketOverviewPaneForScope(PendingTicketOverviewScope);
ClearTicketOverviewTrayNotification();
if (TryHandleTicketOverviewNotificationClick(searchView))
return;
}
#if isDemo
if (searchView.IsVisible)
@@ -278,9 +272,29 @@ namespace FasdDesktopUi
finally
{
LogMethodEnd(CM);
}
}
}
}
#region Ticketübersicht
private bool TryHandleTicketOverviewNotificationClick(SearchPageView searchView)
{
if (searchView == null)
return false;
if (!HasPendingTicketOverviewNotification())
return false;
if (!searchView.IsVisible)
searchView.ActivateSearchView();
else
searchView.BringToFrontPreserveState();
searchView.ShowTicketOverviewPaneForScope(PendingTicketOverviewScope);
ClearTicketOverviewTrayNotification();
return true;
}
private void NotifyIcon_BalloonTipClicked(object sender, EventArgs e)
{
try
@@ -294,11 +308,11 @@ namespace FasdDesktopUi
LogException(E);
}
}
private bool HasPendingTicketOverviewNotification()
{
return _ticketTrayNotification?.HasNotification ?? false;
}
private bool HasPendingTicketOverviewNotification()
{
return _ticketTrayNotification?.HasNotification ?? false;
}
public void ShowTicketOverviewTrayNotification(string message)
{
@@ -331,9 +345,11 @@ namespace FasdDesktopUi
}
public TileScope? PendingTicketOverviewScope => _pendingTicketOverviewScope;
private System.Windows.Forms.ToolStripItem SetUpNotifyIconLanguageOption()
{
#endregion
private System.Windows.Forms.ToolStripItem SetUpNotifyIconLanguageOption()
{
try
{
var output = new System.Windows.Forms.ToolStripMenuItem() { Text = cMultiLanguageSupport.GetItem("Menu.SelectLanguage") };

View File

@@ -36,9 +36,26 @@ namespace FasdDesktopUi.Pages.SearchPage
private static SearchPageView _instance = null;
private const int WM_NCHITTEST = 0x0084;
private const int HTTRANSPARENT = -1;
#region Ticketübersicht
private readonly HashSet<TileScope> _ticketOverviewNotificationScopesPrimed = new HashSet<TileScope>();
private bool _ticketOverviewFirstEventHandled;
private readonly HashSet<TileScope> _ticketOverviewInitWasEmptyScopes = new HashSet<TileScope>();
private bool _ticketOverviewAutoContinueActive;
private DispatcherTimer _ticketOverviewAutoContinueFallbackTimer;
private EventHandler _ticketOverviewAutoContinueCaseChangedHandler;
private bool _renderTicketOverviewUserNames = false;
private readonly HashSet<cSearchHistorySearchResultEntry> _ticketOverviewHistoryEntries = new HashSet<cSearchHistorySearchResultEntry>();
private const string DemoTicketHasDetailsInfoKey = "Demo.HasTicketDetails";
// Event zum auslösen wenn Toggle geändert wird
public event EventHandler<bool> FilterToggleCheckedChanged;
// Aktueller Zustand der Checkbox
public bool IsFilterChecked => FilterCheckbox.IsChecked == true;
#endregion
public static SearchPageView Instance
{
get
@@ -47,25 +64,17 @@ namespace FasdDesktopUi.Pages.SearchPage
}
}
private cF4sdPipeServer _pipeServer;
private cHotKeyManager _hotKeyManager;
private cF4sdPipeServer _pipeServer;
private cHotKeyManager _hotKeyManager;
private CancellationTokenSource _searchCancellationTokenSource = new CancellationTokenSource();
private bool _isActivating = false;
private cF4sdApiSearchResultRelation preSelectedRelation = null;
private bool _renderTicketOverviewUserNames = false;
private readonly HashSet<cSearchHistorySearchResultEntry> _ticketOverviewHistoryEntries = new HashSet<cSearchHistorySearchResultEntry>();
private const string DemoTicketHasDetailsInfoKey = "Demo.HasTicketDetails";
// Event zum auslösen wenn Toggle geändert wird
public event EventHandler<bool> FilterToggleCheckedChanged;
private cF4sdApiSearchResultRelation preSelectedRelation = null;
// Aktueller Zustand der Checkbox
public bool IsFilterChecked => FilterCheckbox.IsChecked == true;
private readonly IRelationService _relationService = new RelationService();
public SupportCaseSearchService SearchService { get; }
private readonly IRelationService _relationService = new RelationService();
public SupportCaseSearchService SearchService { get; }
private SearchPageView()
{
@@ -166,114 +175,14 @@ namespace FasdDesktopUi.Pages.SearchPage
BodyStack_SearchResults.Visibility = (isVisible || SearchResultBorder.IsVisible) ? Visibility.Visible : Visibility.Collapsed;
ScheduleSearchResultMaxHeightUpdate();
}
private bool CheckTicketOverviewAvailability()
public void ShowLoadingTextItem(string itemText)
{
return cFasdCockpitConfig.Instance?.Global?.TicketConfiguration?.ShowOverview == true;
SetSearchHistoryVisibility(false);
ResultMenu.ShowLoadingTextItem(itemText);
}
private void UpdateTicketOverviewAvailability()
public void ShowSearchRelations(cSearchHistorySearchResultEntry searchHistoryEntry, IRelationService relationService, ISearchUiProvider searchUiProvider)
{
var enabled = CheckTicketOverviewAvailability();
var service = TicketOverviewUpdateService.Instance;
service?.UpdateAvailability(enabled);
if (enabled)
_ = service?.FetchAsync();
if (!enabled)
{
if (Dispatcher.CheckAccess())
{
ApplyTicketOverviewDisabledState();
}
else
{
Dispatcher.Invoke(ApplyTicketOverviewDisabledState);
}
}
}
private void ApplyTicketOverviewDisabledState()
{
_renderTicketOverviewUserNames = false;
_ticketOverviewNotificationScopesPrimed.Clear();
_ticketOverviewFirstEventHandled = false;
_ticketOverviewInitWasEmptyScopes.Clear();
SetTicketOverviewVisibility(false);
(Application.Current as App)?.ClearTicketOverviewTrayNotification();
}
private void SetTicketOverviewVisibility(bool isVisible)
{
var b = isVisible;
if (!CheckTicketOverviewAvailability())
b = false;
BodyStack_TicketOverview.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
TicketOverviewBorder.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
FilterCheckbox.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
RoleLabel.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
OwnTicketsLabel.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
TicketOverviewLabel.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
ScheduleSearchResultMaxHeightUpdate();
}
public void ShowLoadingTextItem(string itemText)
{
SetSearchHistoryVisibility(false);
ResultMenu.ShowLoadingTextItem(itemText);
}
public void ShowTicketOverviewPane()
{
Dispatcher.Invoke(() =>
{
bool overviewAlreadyVisible = TicketOverviewBorder.Visibility == Visibility.Visible;
SetTicketOverviewVisibility(true);
if (!overviewAlreadyVisible)
{
SetSearchResultVisibility(false);
SetSearchHistoryVisibility(false);
TicketOverviewUc?.ResetSelection();
}
TicketOverviewUc?.RefreshHighlightState(IsFilterChecked);
var app = Application.Current as FasdDesktopUi.App;
app?.ClearTicketOverviewTrayNotification();
});
}
public void ShowTicketOverviewPaneForScope(TileScope? scope)
{
if (scope.HasValue)
{
Dispatcher.Invoke(() =>
{
if (TicketOverviewBorder.Visibility == Visibility.Visible)
return;
var useRoleScope = scope.Value == TileScope.Role;
if (FilterCheckbox != null && FilterCheckbox.IsChecked != useRoleScope)
FilterCheckbox.IsChecked = useRoleScope;
});
}
ShowTicketOverviewPane();
}
internal void CloseTicketOverviewResults()
{
_renderTicketOverviewUserNames = false;
ResultMenu.ShowSearchResults(new cFilteredResults(), null, this);
ResultMenu.SetHeaderText(string.Empty);
SetSearchResultVisibility(false);
SetTicketOverviewVisibility(true);
}
public void ShowSearchRelations(cSearchHistorySearchResultEntry searchHistoryEntry, IRelationService relationService, ISearchUiProvider searchUiProvider)
{
try
{
_renderTicketOverviewUserNames = searchHistoryEntry != null && _ticketOverviewHistoryEntries.Contains(searchHistoryEntry);
@@ -406,34 +315,38 @@ namespace FasdDesktopUi.Pages.SearchPage
}
}
private void ShowExternalSearchInfo(string strInfo, cFasdApiSearchResultCollection resultEntry, enumF4sdSearchResultClass Class)
{
var filteredResults = new cFilteredResults(resultEntry) { AutoContinue = true };
var _t = ShowExternalSearchInfoAsync(strInfo, filteredResults, Class);
}
private async Task ShowExternalSearchInfoAsync(string strInfo, cFilteredResults result, enumF4sdSearchResultClass Class)
{
try
{
await this.Dispatcher.InvokeAsync(async () =>
private void ShowExternalSearchInfo(string strInfo, cFasdApiSearchResultCollection resultEntry, enumF4sdSearchResultClass Class)
{
var filteredResults = new cFilteredResults(resultEntry) { AutoContinue = true };
var _t = ShowExternalSearchInfoAsync(strInfo, filteredResults, Class, suppressUi: false);
}
private async Task ShowExternalSearchInfoAsync(string strInfo, cFilteredResults result, enumF4sdSearchResultClass Class, bool suppressUi)
{
try
{
await this.Dispatcher.InvokeAsync(async () =>
{
try
{
await SearchBarUc.SetFixedSearchResultAsync(Class, strInfo, result);
await SearchBarUc.SetFixedSearchResultAsync(Class, strInfo, result);
if (result.AutoContinue && result.Results?.Count == 1)
{
ResultMenu.IndexOfSelectedResultItem = 0;
ResultMenu.SelectCurrentResultItem();
}
Show();
}
catch (Exception E)
{
LogException(E);
}
{
ResultMenu.IndexOfSelectedResultItem = 0;
ResultMenu.SelectCurrentResultItem();
}
if (!suppressUi && !_ticketOverviewAutoContinueActive)
{
Show();
Activate();
}
}
catch (Exception E)
{
LogException(E);
}
});
}
catch (Exception E)
@@ -884,11 +797,11 @@ namespace FasdDesktopUi.Pages.SearchPage
}
}
private void HandleRelationsFound(object sender, StagedSearchResultRelationsEventArgs e)
{
try
{
Dispatcher.Invoke(() =>
private void HandleRelationsFound(object sender, StagedSearchResultRelationsEventArgs e)
{
try
{
Dispatcher.Invoke(() =>
{
var first = e.RelatedTo.FirstOrDefault();
var relationSearchResult = new cSearchHistorySearchResultEntry(first.DisplayName, first.DisplayName, e.RelatedTo.ToList(), e.StagedResultRelations.Relations.ToList(), this);
@@ -900,9 +813,110 @@ namespace FasdDesktopUi.Pages.SearchPage
catch (Exception ex)
{
LogException(ex);
}
}
}
}
#region Ticketübersicht
private bool CheckTicketOverviewAvailability()
{
return cFasdCockpitConfig.Instance?.Global?.TicketConfiguration?.ShowOverview == true;
}
private void UpdateTicketOverviewAvailability()
{
var enabled = CheckTicketOverviewAvailability();
var service = TicketOverviewUpdateService.Instance;
service?.UpdateAvailability(enabled);
if (enabled)
_ = service?.FetchAsync();
if (!enabled)
{
if (Dispatcher.CheckAccess())
{
ApplyTicketOverviewDisabledState();
}
else
{
Dispatcher.Invoke(ApplyTicketOverviewDisabledState);
}
}
}
private void ApplyTicketOverviewDisabledState()
{
_renderTicketOverviewUserNames = false;
_ticketOverviewNotificationScopesPrimed.Clear();
_ticketOverviewFirstEventHandled = false;
_ticketOverviewInitWasEmptyScopes.Clear();
SetTicketOverviewVisibility(false);
(Application.Current as App)?.ClearTicketOverviewTrayNotification();
}
private void SetTicketOverviewVisibility(bool isVisible)
{
var b = isVisible;
if (!CheckTicketOverviewAvailability())
b = false;
BodyStack_TicketOverview.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
TicketOverviewBorder.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
FilterCheckbox.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
RoleLabel.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
OwnTicketsLabel.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
TicketOverviewLabel.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
ScheduleSearchResultMaxHeightUpdate();
}
public void ShowTicketOverviewPane()
{
Dispatcher.Invoke(() =>
{
bool overviewAlreadyVisible = TicketOverviewBorder.Visibility == Visibility.Visible;
SetTicketOverviewVisibility(true);
if (!overviewAlreadyVisible)
{
SetSearchResultVisibility(false);
SetSearchHistoryVisibility(false);
TicketOverviewUc?.ResetSelection();
}
TicketOverviewUc?.RefreshHighlightState(IsFilterChecked);
var app = Application.Current as FasdDesktopUi.App;
app?.ClearTicketOverviewTrayNotification();
});
}
public void ShowTicketOverviewPaneForScope(TileScope? scope)
{
if (scope.HasValue)
{
Dispatcher.Invoke(() =>
{
if (TicketOverviewBorder.Visibility == Visibility.Visible)
return;
var useRoleScope = scope.Value == TileScope.Role;
if (FilterCheckbox != null && FilterCheckbox.IsChecked != useRoleScope)
FilterCheckbox.IsChecked = useRoleScope;
});
}
ShowTicketOverviewPane();
}
internal void CloseTicketOverviewResults()
{
_renderTicketOverviewUserNames = false;
ResultMenu.ShowSearchResults(new cFilteredResults(), null, this);
ResultMenu.SetHeaderText(string.Empty);
SetSearchResultVisibility(false);
SetTicketOverviewVisibility(true);
}
private void TicketOverviewUpdateService_OverviewCountsChanged(object sender, TicketOverviewCountsChangedEventArgs e)
{
try
@@ -994,14 +1008,17 @@ namespace FasdDesktopUi.Pages.SearchPage
relation.Infos.TryGetValue("UserSid", out sids);
}
return RunTicketSearchAsync(ticketName, ticketId, userName, sids);
return RunTicketSearchAsync(ticketName, ticketId, userName, sids, suppressUi: true);
}
private Task RunTicketSearchAsync(string ticketName, Guid ticketId, string userName, string sids)
private Task RunTicketSearchAsync(string ticketName, Guid ticketId, string userName, string sids, bool suppressUi = false)
{
if (ticketId == Guid.Empty)
return Task.CompletedTask;
if (suppressUi)
BeginTicketOverviewAutoContinue(TimeSpan.FromSeconds(6));
return Task.Run(async () =>
{
try
@@ -1012,10 +1029,19 @@ namespace FasdDesktopUi.Pages.SearchPage
if (_result is null || _result.Count == 0 || _result.First().Value.Count == 0)
{
LogEntry($"No corresponding user could be found for ticket '{ticketName}'", LogLevels.Warning);
if (suppressUi)
EndTicketOverviewAutoContinue(showSearch: true);
return;
}
var userId = _result.Values.First().First().id;
if (userId == Guid.Empty)
{
LogEntry($"No valid user id could be found for ticket '{ticketName}'", LogLevels.Warning);
if (suppressUi)
EndTicketOverviewAutoContinue(showSearch: true);
return;
}
var _ticketRelation = new cF4sdApiSearchResultRelation()
{
Type = enumF4sdSearchResultClass.Ticket,
@@ -1040,15 +1066,96 @@ namespace FasdDesktopUi.Pages.SearchPage
var filteredResults = new cFilteredResults(_result) { AutoContinue = true, PreSelectedRelation = _ticketRelation };
var strInfo = string.Format(cMultiLanguageSupport.GetItem("Searchbar.TicketSearch.Info"), ticketName);
await ShowExternalSearchInfoAsync(strInfo, filteredResults, enumF4sdSearchResultClass.Ticket);
await ShowExternalSearchInfoAsync(strInfo, filteredResults, enumF4sdSearchResultClass.Ticket, suppressUi);
}
catch (Exception E)
{
LogException(E);
if (suppressUi)
EndTicketOverviewAutoContinue(showSearch: true);
}
});
}
private void BeginTicketOverviewAutoContinue(TimeSpan fallbackTimeout)
{
if (Dispatcher.CheckAccess())
BeginTicketOverviewAutoContinueCore(fallbackTimeout);
else
Dispatcher.Invoke(() => BeginTicketOverviewAutoContinueCore(fallbackTimeout));
}
private void BeginTicketOverviewAutoContinueCore(TimeSpan fallbackTimeout)
{
if (_ticketOverviewAutoContinueActive)
return;
_ticketOverviewAutoContinueActive = true;
SearchBarUc.IsHitTestVisible = false;
ResultMenu.IsHitTestVisible = false;
SearchHistory.IsHitTestVisible = false;
BodyStack_TicketOverview.IsHitTestVisible = false;
FilterCheckbox.IsHitTestVisible = false;
SetSearchHistoryVisibility(false);
SetSearchResultVisibility(false);
_ticketOverviewAutoContinueCaseChangedHandler = (sender, args) => EndTicketOverviewAutoContinue(showSearch: false);
cSupportCaseDataProvider.CaseChanged += _ticketOverviewAutoContinueCaseChangedHandler;
_ticketOverviewAutoContinueFallbackTimer = new DispatcherTimer { Interval = fallbackTimeout };
_ticketOverviewAutoContinueFallbackTimer.Tick += TicketOverviewAutoContinueFallbackTimer_Tick;
_ticketOverviewAutoContinueFallbackTimer.Start();
}
private void TicketOverviewAutoContinueFallbackTimer_Tick(object sender, EventArgs e)
{
EndTicketOverviewAutoContinue(showSearch: true);
}
private void EndTicketOverviewAutoContinue(bool showSearch)
{
if (Dispatcher.CheckAccess())
EndTicketOverviewAutoContinueCore(showSearch);
else
Dispatcher.Invoke(() => EndTicketOverviewAutoContinueCore(showSearch));
}
private void EndTicketOverviewAutoContinueCore(bool showSearch)
{
if (!_ticketOverviewAutoContinueActive)
return;
_ticketOverviewAutoContinueActive = false;
if (_ticketOverviewAutoContinueFallbackTimer != null)
{
_ticketOverviewAutoContinueFallbackTimer.Stop();
_ticketOverviewAutoContinueFallbackTimer.Tick -= TicketOverviewAutoContinueFallbackTimer_Tick;
_ticketOverviewAutoContinueFallbackTimer = null;
}
if (_ticketOverviewAutoContinueCaseChangedHandler != null)
{
cSupportCaseDataProvider.CaseChanged -= _ticketOverviewAutoContinueCaseChangedHandler;
_ticketOverviewAutoContinueCaseChangedHandler = null;
}
SearchBarUc.IsHitTestVisible = true;
ResultMenu.IsHitTestVisible = true;
SearchHistory.IsHitTestVisible = true;
BodyStack_TicketOverview.IsHitTestVisible = true;
FilterCheckbox.IsHitTestVisible = true;
if (showSearch)
{
SetSearchResultVisibility(true);
Show();
Activate();
}
}
private void PrimeTicketOverviewScope(TileScope scope)
{
if (_ticketOverviewNotificationScopesPrimed.Add(scope))
@@ -1249,11 +1356,11 @@ namespace FasdDesktopUi.Pages.SearchPage
return "TicketOverview.Column.Heading.New";
}
private static string GetScopeRowLabel(TileScope scope, string rowKey, string rowLabel)
{
string suffix = null;
if (string.Equals(rowKey, "TicketOverview.Row.Heading.Tickets", StringComparison.OrdinalIgnoreCase))
suffix = "Tickets";
private static string GetScopeRowLabel(TileScope scope, string rowKey, string rowLabel)
{
string suffix = null;
if (string.Equals(rowKey, "TicketOverview.Row.Heading.Tickets", StringComparison.OrdinalIgnoreCase))
suffix = "Tickets";
else if (string.Equals(rowKey, "TicketOverview.Row.Heading.Incidents", StringComparison.OrdinalIgnoreCase))
suffix = "Incidents";
else if (string.Equals(rowKey, "TicketOverview.Row.Heading.UnassignedTickets", StringComparison.OrdinalIgnoreCase))
@@ -1262,75 +1369,9 @@ namespace FasdDesktopUi.Pages.SearchPage
var translationKey = scope == TileScope.Role
? $"TicketOverview.ScopeRow.Role.{suffix}"
: $"TicketOverview.ScopeRow.Personal.{suffix}";
return cMultiLanguageSupport.GetItem(translationKey) ?? rowLabel;
}
private IntPtr SearchViewWindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_NCHITTEST)
{
if (!IsPointWithinInteractiveBounds(lParam))
{
handled = true;
return new IntPtr(HTTRANSPARENT);
}
}
return IntPtr.Zero;
}
private bool IsPointWithinInteractiveBounds(IntPtr lParam)
{
if (!IsLoaded || MainBorder == null || !MainBorder.IsLoaded)
return true;
if (MainBorder.ActualWidth <= 0 || MainBorder.ActualHeight <= 0)
return true;
var screenPoint = ExtractScreenPoint(lParam);
var windowPoint = PointFromScreen(screenPoint);
if (!(InputHitTest(windowPoint) is DependencyObject hitElement))
return false;
return IsDescendantOf(hitElement, MainBorder);
}
private static Point ExtractScreenPoint(IntPtr lParam)
{
int value = unchecked((int)(long)lParam);
short x = (short)(value & 0xFFFF);
short y = (short)((value >> 16) & 0xFFFF);
return new Point(x, y);
}
private static bool IsDescendantOf(DependencyObject element, DependencyObject ancestor)
{
while (element != null)
{
if (element == ancestor)
return true;
element = GetParent(element);
}
return false;
}
private static DependencyObject GetParent(DependencyObject current)
{
if (current == null)
return null;
if (current is Visual || current is System.Windows.Media.Media3D.Visual3D)
return VisualTreeHelper.GetParent(current);
if (current is System.Windows.ContentElement contentElement)
return System.Windows.ContentOperations.GetParent(contentElement);
return LogicalTreeHelper.GetParent(current);
}
return cMultiLanguageSupport.GetItem(translationKey) ?? rowLabel;
}
private void ShowTicketOverviewNotification(string message)
{
@@ -1654,11 +1695,79 @@ namespace FasdDesktopUi.Pages.SearchPage
relation.Infos["UserGuid"] = userId.ToString();
}
}
private void UpdateSearchResults(cFilteredResults filteredResults)
{
this.Dispatcher.Invoke(new Action(() =>
{
#endregion
private IntPtr SearchViewWindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_NCHITTEST)
{
if (!IsPointWithinInteractiveBounds(lParam))
{
handled = true;
return new IntPtr(HTTRANSPARENT);
}
}
return IntPtr.Zero;
}
private bool IsPointWithinInteractiveBounds(IntPtr lParam)
{
if (!IsLoaded || MainBorder == null || !MainBorder.IsLoaded)
return true;
if (MainBorder.ActualWidth <= 0 || MainBorder.ActualHeight <= 0)
return true;
var screenPoint = ExtractScreenPoint(lParam);
var windowPoint = PointFromScreen(screenPoint);
if (!(InputHitTest(windowPoint) is DependencyObject hitElement))
return false;
return IsDescendantOf(hitElement, MainBorder);
}
private static Point ExtractScreenPoint(IntPtr lParam)
{
int value = unchecked((int)(long)lParam);
short x = (short)(value & 0xFFFF);
short y = (short)((value >> 16) & 0xFFFF);
return new Point(x, y);
}
private static bool IsDescendantOf(DependencyObject element, DependencyObject ancestor)
{
while (element != null)
{
if (element == ancestor)
return true;
element = GetParent(element);
}
return false;
}
private static DependencyObject GetParent(DependencyObject current)
{
if (current == null)
return null;
if (current is Visual || current is System.Windows.Media.Media3D.Visual3D)
return VisualTreeHelper.GetParent(current);
if (current is System.Windows.ContentElement contentElement)
return System.Windows.ContentOperations.GetParent(contentElement);
return LogicalTreeHelper.GetParent(current);
}
private void UpdateSearchResults(cFilteredResults filteredResults)
{
this.Dispatcher.Invoke(new Action(() =>
{
try
{
_renderTicketOverviewUserNames = false;