如何检测FlowDocumentScrollViewer视图中可见的Section?
WPF中检测FlowDocumentScrollViewer内可见的Section
要检测FlowDocumentScrollViewer中当前可视的Section,核心是对比Section的布局区域和滚动控件的可视范围是否存在交集。以下是具体实现方案:
实现步骤
- 在ScrollChanged事件中,获取ScrollViewer的可视区域矩形
- 遍历FlowDocument中的所有Section,将每个Section的布局坐标转换为相对于ScrollViewer的坐标
- 判断Section的矩形区域是否与ScrollViewer的可视区域有重叠,重叠则标记为可见
修改后的后台代码
替换原Sv_ScrollChanged方法,完整代码如下:
using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace WpfApp1 { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void FlowDoc_Loaded(object sender, RoutedEventArgs e) { ScrollViewer sv = flowDoc.Template.FindName("PART_ContentHost", flowDoc) as ScrollViewer; sv.ScrollChanged += Sv_ScrollChanged; } private void Sv_ScrollChanged(object sender, ScrollChangedEventArgs e) { var scrollViewer = sender as ScrollViewer; if (scrollViewer == null) return; // 获取ScrollViewer的可视区域 Rect viewportRect = new Rect(0, scrollViewer.VerticalOffset, scrollViewer.ViewportWidth, scrollViewer.ViewportHeight); foreach (Section section in flowdoc1.Blocks) { // 获取Section的Visual对象 var visual = section as Visual; if (visual == null) continue; // 将Section的坐标转换为相对于ScrollViewer的坐标 GeneralTransform transform = visual.TransformToAncestor(scrollViewer); Rect sectionRect = transform.TransformBounds(new Rect(0, 0, section.ActualWidth, section.ActualHeight)); // 判断是否有交集(即是否可见) bool isVisible = viewportRect.IntersectsWith(sectionRect); // 这里可以根据isVisible做后续处理,比如打印或标记 if (isVisible) { System.Diagnostics.Debug.WriteLine($"可见Section: {section.Name}"); } } } } }
关键代码说明
- 获取可视区域:通过
scrollViewer.VerticalOffset、ViewportWidth和ViewportHeight构建ScrollViewer当前的可视矩形 - 坐标转换:使用
TransformToAncestor将Section自身的布局坐标转换为相对于ScrollViewer的坐标,确保坐标系统统一 - 交集判断:调用
IntersectsWith方法判断两个矩形是否重叠,只要有重叠部分就认为该Section处于可视范围内
如果需要更严格的可见判断(比如Section必须完全在可视区域内),可以将IntersectsWith替换为判断viewportRect.Contains(sectionRect)。
内容的提问来源于stack exchange,提问作者Kiran Shahi
相关产品推荐
相关产品推荐

