![](/img/trans.png)
[英]TableLayoutPanel GetControlFromPosition does not get non-visible controls. How do you access a non-visible control at a specified position?
[英]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.GetChildrenCount
和VisualTreeHelper.GetChild()
递归地下降Visual树,并使用此过程检查每个Visual:
new Rect(0, 0, visual.ActualWidth, visual.ActualHeight)
获取每个Visual的边界框。 这将为您提供Visual坐标系中的边界框。 visual.TransformToAncestor(viewer)
返回的转换将边界框转换为查看器的坐标系。 这将告诉您可见区域中的所有视觉效果。 如果要映射到诸如<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.