2009-11-16 70 views
1

我有一个FlowDocument,里面有很多内容。我需要获取当前处于可见区域的控件。按位置获取可见控件

通过以下代码,我可以获得当前的滚动位置。

DependencyObject obj = FlowDocumentScrollViewerCtrl; 

do 
{ 
    if (VisualTreeHelper.GetChildrenCount(obj) > 0) 
    { 
     obj = VisualTreeHelper.GetChild(obj as Visual, 0); 
    } 
} 
while (!(obj is ScrollViewer)); 

ScrollViewer sv = obj as ScrollViewer; 

如何获取可见区域内的控件?

回答

0

的方法之一是使用VisualTreeHelper.GetChildrenCountVisualTreeHelper.GetChild()使用此过程递归下降的视觉树和检查每个视觉:

  1. 扔掉任何可视一点意思都没有到您的代码(例如,您可能只关心Controls)
  2. 使用new Rect(0, 0, visual.ActualWidth, visual.ActualHeight)获取每个Visual的边界框。这会给你在Visual的坐标系中的边界框。
  3. 使用visual.TransformToAncestor(viewer)返回的变换将边界框转换为查看器的坐标系。
  4. 检查转换的视觉边界框是否与观察者的边界框相交。粗略的检查可以通过获取视觉边界框角的最小值和最大值X和Y来完成,并且每次只比较一个轴。这比完整的矩形交叉点更容易,并且应该用于大多数目的。

这会告诉你在可见区域的所有视觉效果。如果您想映射到FrameworkContentElement,例如<Paragraph>,只需查看您在树步行中跑过的ContentPresenter的内容属性。

0

感谢雷为您的答案。我跟在某些方面你的秘诀昨天和多数民众赞成在工作代码我的问题:

public class FrameworkElementInfo 
{ 
    Point _position    = new Point(); 
    FrameworkElement _element = null; 

    public Point Position 
    { 
     get { return _position; } 
     set { _position = value; } 
    } 

    public FrameworkElement FrameworkElement 
    { 
     get { return _element; } 
     set { _element = value; } 
    } 
} 

public class ScrollViewPositionManager 
{ 
    ScrollViewer _scrollViewer    = null; 
    List<FrameworkElementInfo> _elements = new List<FrameworkElementInfo>(); 
    double _zoom       = 100.0; 

    public ScrollViewPositionManager(ScrollViewer scrollViewer, double zoom) 
    { 
     _scrollViewer = scrollViewer; 
     _zoom = zoom; 
    } 

    public void RegisterElement(FrameworkElement element, Boolean registerOnly) 
    { 
     FrameworkElementInfo info = new FrameworkElementInfo(); 

     if (!registerOnly) info.Position = CalculatePosition(element); 
     info.FrameworkElement = element; 

     _elements.Add(info); 
    } 

    public void RecalculatePositions() 
    { 
     int Counter = 0; 

     foreach(FrameworkElementInfo info in _elements) 
     { 
      Counter += 1; 
      info.Position = CalculatePosition(info.FrameworkElement); 
     } 
    } 

    public List<FrameworkElement> GetElementsInViewPort() 
    { 
     List<FrameworkElement> elements = new List<FrameworkElement>(); 

     double verticalOffsetHigh = _scrollViewer.ViewportHeight + _scrollViewer.VerticalOffset; 

     foreach (FrameworkElementInfo info in _elements) 
     { 
      Point point = info.Position; 

      if (point.Y >= _scrollViewer.VerticalOffset && 
       point.Y <= verticalOffsetHigh) 
      { 
       elements.Add(info.FrameworkElement); 
      } 
     } 

     return elements; 
    } 

    private Point CalculatePosition(FrameworkElement element) 
    { 
     GeneralTransform elementTransform = element.TransformToAncestor(_scrollViewer); 
     Point elementPoint = elementTransform.Transform(new Point(0, 0)); 
     Point transformedPoint = new Point(elementPoint.X, elementPoint.Y); 

     transformedPoint = GetZoomedPoint(elementPoint, _zoom, _scrollViewer.HorizontalOffset, _scrollViewer.VerticalOffset); 

     return transformedPoint; 
    } 

    static public Point GetZoomedPoint(Point unzoomedPoint, double zoom, double offsetX, double offsetY) 
    { 
     Point zoomedPoint = new Point(); 

     double zoomFactor = 100.0/zoom; 

     zoomedPoint.X = offsetX + unzoomedPoint.X * zoomFactor; 
     zoomedPoint.Y = offsetY + unzoomedPoint.Y * zoomFactor; 

     return zoomedPoint; 
    } 

    public int ElementCount 
    { 
     get { return _elements.Count; } 
    } 

    public FrameworkElement GetFirstElement() 
    { 
     FrameworkElement firstElement = null; 

     if(_elements.Count > 0) firstElement = _elements[0].FrameworkElement; 

     return firstElement; 
    } 

    public FrameworkElement GetLastElement() 
    { 
     FrameworkElement lastElement = null; 

     if (_elements.Count > 0) lastElement = _elements[_elements.Count-1].FrameworkElement; 

     return lastElement; 
    } 

    public FrameworkElement GetNextElement(FrameworkElement element) 
    { 
     FrameworkElement nextElement = null; 
     int index = GetElementIndex(element); 

     if(index != -1 && index != _elements.Count -1) 
     {   
      nextElement = _elements[index + 1].FrameworkElement; 
     } 

     return nextElement; 
    } 

    public FrameworkElement GetPreviousElement(FrameworkElement element) 
    { 
     FrameworkElement previousElement = null; 
     int index = GetElementIndex(element); 

     if (index > 1) 
     { 
      previousElement = _elements[index - 1].FrameworkElement; 
     } 

     return previousElement; 
    } 

    public int GetElementIndex(FrameworkElement element) 
    { 
     return _elements.FindIndex(
          delegate(FrameworkElementInfo currentElement) 
          { 
           if(currentElement.FrameworkElement == element) return true; 
           return false; 
          } 
     ); 
    } 
} 

我用一个寄存器功能感兴趣的元素,只对他们的工作。我认为缩放对于FlowDocument来说只是必需的。该代码应该适用于使用ScrollViewer的每个控件。 如果有人可以发表评论,如果这是一个实际的解决方案,我将不胜感激。