3

我有一个ScrollViewer在其中,我有一个ItemsControlItemsControl绑定到ObservableCollection一个. 有ItemsControl一个ItemTemplate,其中我提供了一个TextBox来显示数据。

数据正在正确显示。我已经为每一个添加了一个弹出窗口,TextBox以显示放置目标为 Top 的附加数据。

我面临的问题是,当我滚动某个项目时,我需要隐藏弹出窗口并在项目出现时再次显示它。

我已经订阅了滚动查看器的ScrollChanged事件,但是如何获取TextBox超出范围以隐藏弹出窗口的项目/?

4

2 回答 2

3

您可以使用 Lester 的 WPF\SL 博客上的Determining the Visibility of Elements inside ScrollViewer 一文中的方法来确定特定项目是否可见ScrollViewer。从那个博客:

// 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.
}

显然,要使其工作,您需要向bool IsPopupOpen数据绑定到属性的数据对象添加一个新TextBox.Text属性。然后你也需要Bind这个Popup.IsOpen属性:

<Popup IsOpen="{Binding IsPopupOpen}" StaysOpen="False" ... />

更新>>>

当滚动a 时,该ScrollViewer.ScrollChanged事件将被经常调用。ScrollViewer直接在该事件处理程序中执行任何代码确实是不明智的,但是该ScrollChangedEventArgs对象具有一些可以帮助我们的属性。有关这些属性的完整详细信息,请查看 MSDN 上的ScrollChangedEventArgsClass页面。

您可以在名为的事件处理程序中访问两个属性,VerticalChange它们应该向您显示自上次事件以来滚动HorizontalChange了多少。ScrollViewer[现在已经有一段时间了,所以我不能保证它们是正确的属性,但是如果您在事件处理程序中使用 MSDN 上的“ScrollChangedEventArgs.VerticalChange属性”页面中的示例代码,读出的内容应该会给您一个线索,哪些是要使用的正确属性。]

因此,找到相关属性后,您可以在处理程序中使用它们来确定是否执行您的代码......尝试这样的事情:

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;
}

如果这里有错误,请原谅我,因为我目前无法在 Visual Studio 中检查这一点,但希望你能明白……本质上,这就像我们正在“过滤”掉一些事件。

于 2013-10-17T08:54:23.987 回答
2

在此处查看此问题,该问题讨论了确定 ScrollViewer 中对象的可见性。

基本的辅助方法:

private bool IsUserVisible(FrameworkElement element, FrameworkElement container)
{
    if (!element.IsVisible)
        return false;

    Rect bounds = element.TransformToAncestor(container).TransformBounds(new Rect(0.0, 0.0, element.ActualWidth, element.ActualHeight));
    Rect rect = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight);
    return rect.Contains(bounds.TopLeft) || rect.Contains(bounds.BottomRight);
}

以及一个执行您想要执行的操作的示例函数:

private void Scroll_Changed(object sender, ScrollChangedEventArgs e)
{
    Object o = sender;
    bool elementIsVisible = false;

    foreach (FrameworkElement child in this.stackPanel1.Children)
    {
        if (child != null)
        {
            elementIsVisible = this.IsUserVisible(child, this.scroller);

            if (!elementIsVisible)
            {
                // Logic to disable popups here...
            }
        }
    }
}
于 2013-10-17T09:05:57.333 回答