繁体   English   中英

按位置获取可见控件

[英]Get visible controls by position

我有一个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;

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

一种方法是使用VisualTreeHelper.GetChildrenCountVisualTreeHelper.GetChild()递归地下降Visual树,并使用此过程检查每个Visual:

  1. 扔掉任何对您的代码不感兴趣的视觉效果(例如,您可能只关心控件)
  2. 使用new Rect(0, 0, visual.ActualWidth, visual.ActualHeight)获取每个Visual的边界框。 这将为您提供Visual坐标系中的边界框。
  3. 使用visual.TransformToAncestor(viewer)返回的转换将边界框转换为查看器的坐标系。
  4. 检查以查看转换后的视觉效果的边界框是否与查看器的边界框相交。 可以通过获取可视边界框角的最小和最大X和Y并一次比较一个轴来进行粗略检查。 这比完整的矩形相交要容易,并且应可用于大多数目的。

这将告诉您可见区域中的所有视觉效果。 如果要映射到诸如<Paragraph>类的FrameworkContentElement ,只需签出您在树步中遇到的ContentPresenter的Content属性。

感谢Ray的回答。 昨天我在某些方面遵循了您的提示,这就是解决我的问题的有效代码:

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的每个控件上起作用。 如果这是一个可行的解决方案,那么如果有人可以对此发表评论,我将不胜感激。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM