alielie
2026-09-10 f3889f2d36c50cf99468594854def9b7ed069fb5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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;
 
        /// <summary>
        /// Processes all UI messages currently in the message queue.
        /// </summary>
        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<T>(object obj)
        {
            if (obj == null)
            {
                return default(T);
            }
 
            if (obj is T target)
            {
                return target;
            }
            return FindControl<T>(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;
            }
        }
 
        /// <summary>
        /// 查找第一个指定类型的子控件
        /// </summary>
        public static T FindVisualChild<T>(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<T>(child);
                if (result != null)
                    return result;
            }
 
            return null;
        }
    }
}