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;
|
}
|
}
|
}
|