Determining the Visibility of Elements inside Scrollviewer
A ScrollViewer is a very handy control. One of the problems, however, is bringing a control to Focus or scrolling to the item. If this is done manually, that’s not an issue. But programmatically hmm.. You can hit some issues. The simplest way is to call the scrollviewer’s ScrollToVerticalOffset() with the offset being the Y co-ordinate. But what if the element is partially visible and you do not want it to scroll. This would require determining if the element is in the ScrollViewers viewport. The way to achieve this is simple.
Suppose ContainedObject is the element inside the Scrollviewer (ScrollViewerObj)
// position of your visual inside the scrollviewer
GeneralTransform childTransform = ContainedObject.TransformToAncestor(ScrollViewerObj);
Rect rectangle = childTransform.TransformBounds(new Rect(new Point(0,0),ContainedObject.RenderSize));
//Check if the elements Rect intersects with that of the scrollviewer's
Rect result = Rect.Intersect(new Rect(new Point(0, 0), ScrollViewerObj.RenderSize),rectangle);
//if result is Empty then the element is not in view
if (result == Rect.Empty)
{
//....
}
else
{
//obj is partially Or completely visible
//skip or bring obj in view.
}
Comments
Anonymous
January 19, 2007
If the element is a FrameworkElement, couldn't you use the BringIntoView method?Anonymous
January 19, 2007
that would not work if you do not want to bring the partially visible object completely into view.Anonymous
January 20, 2007
Could you explain why it would not work? I mean, yes if you wanted to only scroll vertically then you need to do as you listed but if you just want to ensure that an element is in view, that is what the BringIntoView method is designed to do. It allows an element to request to be brought into view without having to worry about what type of container its in and allow the container to perform the action necessary to bring it into view. The ScrollViewer hooks the RequestBringIntoView and brings the element into view if its a descendant of the scroll viewer.Anonymous
January 20, 2007
If its just trying to bring the object into view you are right. BringIntoView always tries to being the whole onject into view. But if the objective is to only bring the object into view if it is not visible then you cannot do this by BringIntoView. A simple scenario could be you are viewing a list of thumbnails and in the view you have 3 images with the image at the bottom being of interest. Now if you call BringIntoView it will try to scroll so that this image is at the top completely in view.Anonymous
January 20, 2007
BringIntoView does not force the item to be displayed at the top (unless the object is so large that even when at the top it would not be fully in view). It just scrolls enough so that the item is in view. If the item is below the visible area, it would scroll it such that the bottom of the element in question is at the bottom of the visible area. I'm not sure what you're point is about being "visible"; I assume you mean in view in which case if the item were already in view, it would do nothing. Also, if the goal is to bring a certain portion of the element into view, you can use the overload that takes a Rect which indicates the portion within element on which BringIntoView is called that should be brought into view.Anonymous
January 20, 2007
Hi Andrew, the point of the post is to show how someone could decide if the object is visible (partially/completely) in the viewport. If its partially visible, a call to bringtoview tries to bring the complete object in view - this may or may not be the objective. There might be several ways of acheving the result - the post documents one approach on how the user could decide whether the obj is in view or not... Scrolling or calling bringintoview depends on the scenario. :)