You can use the method from the Determining the Visibility of Elements inside ScrollViewer article on Lester's WPF\SL Blog to determine whether a particular item is visible in the ScrollViewer
or not. From that blog:
// 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)
{
ContainedObject.IsPopupOpen = false; // <<< Close relevant popup here
}
else
{
//obj is partially Or completely visible
//skip or bring obj in view.
}
Clearly, for this to work, you'll need to add a new bool IsPopupOpen
property to the data object that is data bound to the TextBox.Text
properties. You'll then need to Bind
this to the Popup.IsOpen
property too:
<Popup IsOpen="{Binding IsPopupOpen}" StaysOpen="False" ... />
UPDATE >>>
The ScrollViewer.ScrollChanged
event will get called very often when a ScrollViewer
is scrolled. It would indeed be unwise to perform any code directly in that event handler, however the ScrollChangedEventArgs
object has some properties that can help us. Please take a look on the ScrollChangedEventArgs
Class page on MSDN for full details of these properties.
There are two properties that you will have access to in your event handler named VerticalChange
and HorizontalChange
that should show you how much the ScrollViewer
has been scrolled since the last event. [Now it's been a while, so I can't guarantee that they are the correct properties, but if you use the example code from the ScrollChangedEventArgs.VerticalChange
Property page on MSDN in your event handler, the read out should give you a clue as to which are the correct properties to use.]
So, having found the relevant properties, you can use them in your handler to determine whether to perform your code or not... try something like this:
double totalVerticalChange = 0.0;
double minimumValue = 24.0; // set this to whatever you want as a minimum scroll value
...
private void ScrollViewer_Changed(object sender, ScrollChangedEventArgs e)
{
if (totalVerticalChange + e.VerticalChange >= minimumValue)
{
totalVerticalChange = 0.0;
// perform your functionality here
}
else totalVerticalChange += e.VerticalChange;
}
Please forgive me if there are errors here as I can't check this in Visual Studio at the moment, but hopefully you get the idea... essentially, it's like we are 'filtering' out some of the events.