2009-11-16 72 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的每個控件。 如果有人可以發表評論,如果這是一個實際的解決方案,我將不勝感激。

相關問題