using System.Windows.Media; using System.Windows; using System.Windows.Threading; using System.Windows.Controls; namespace SeqEditor.Util { public class DispatcherHelper { private static readonly DispatcherOperationCallback exitFrameCallback = ExitFrame; /// /// Processes all UI messages currently in the message queue. /// public static void WaitForPriority() { // Create new nested message pump. DispatcherFrame nestedFrame = new DispatcherFrame(); // Dispatch a callback to the current message queue, when getting called, // this callback will end the nested message loop. // The priority of this callback should be lower than that of event message you want to process. DispatcherOperation exitOperation = Dispatcher.CurrentDispatcher.BeginInvoke( DispatcherPriority.ApplicationIdle, exitFrameCallback, nestedFrame); // pump the nested message loop, the nested message loop will immediately // process the messages left inside the message queue. Dispatcher.PushFrame(nestedFrame); // If the "exitFrame" callback is not finished, abort it. if (exitOperation.Status != DispatcherOperationStatus.Completed) { exitOperation.Abort(); } } private static Object ExitFrame(Object state) { DispatcherFrame frame = state as DispatcherFrame; // Exit the nested message loop. frame.Continue = false; return null; } public static T FindControl(object obj) { if (obj == null) { return default(T); } if (obj is T target) { return target; } return FindControl(VisualTreeHelper.GetParent((DependencyObject)obj)); } public static bool IsElementVisibleInScrollViewer(ScrollViewer scrollViewer, DependencyObject element) { if (scrollViewer == null || element == null) return false; // 将 element 转换为 FrameworkElement var frameworkElement = element as FrameworkElement; if (frameworkElement == null) return false; try { // 获取元素相对于 ScrollViewer 的坐标变换 GeneralTransform transform = frameworkElement.TransformToVisual(scrollViewer); // 计算元素在 ScrollViewer 坐标系中的位置和大小 Rect elementRect = new Rect( transform.Transform(new Point(0, 0)), transform.Transform(new Point(frameworkElement.ActualWidth, frameworkElement.ActualHeight)) ); // ScrollViewer 的视区矩形 Rect viewportRect = new Rect( 0, 0, scrollViewer.ViewportWidth, scrollViewer.ViewportHeight ); // 检查是否相交(部分可见也算可见) //return viewportRect.IntersectsWith(elementRect); // 如果需要完全可见,使用以下代码: return viewportRect.Contains(elementRect); } catch (ArgumentException) { // 如果元素尚未加载或不可见,TransformToVisual 可能抛出异常 return false; } } /// /// 查找第一个指定类型的子控件 /// public static T FindVisualChild(DependencyObject parent) where T : DependencyObject { if (parent == null) return null; for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) { var child = VisualTreeHelper.GetChild(parent, i); // 找到指定类型 if (child is T t) return t; // 递归查找 var result = FindVisualChild(child); if (result != null) return result; } return null; } } }