【问题标题】:ItemsControl item, going out of viewItemsControl 项目,消失不见
【发布时间】:2013-10-25 15:43:37
【问题描述】:

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

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

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

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

【问题讨论】:

  • 代码示例将简化此过程并保存所有理论上的“我有一个..”句子
  • 首先,一个 ItemsControl 包含它自己的 ScrollViewer ,其次看看这里的最后一个答案stackoverflow.com/questions/19397780/…
  • 这似乎是最近流行的请求!

标签: wpf wpf-controls itemscontrol


【解决方案1】:

您可以使用 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" ... />

更新>>>

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

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

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

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 中检查这一点,但希望你能明白……本质上,这就像我们正在“过滤”掉一些事件。

【讨论】:

  • 要获得 ContainedObject,他必须迭代他的 ItemsControl 的整个可视项目。
  • @eranotzap,我没有看到您链接帖子中的答案有任何改进,这实际上回答了项目被滚动进入视图的相反问题,但请随时提供更好的答案。
  • @Sheridan,您只需将测试更改为阴性而不是阳性。现在对于所有不可见的项目,您可以禁用弹出窗口并执行您想做的任何其他操作。
  • @Sheridan 我真的不知道该怎么感谢你!您的代码 sn-p 有效,也感谢您的链接。我有一个附加的行为,所以我可以找到一种显示/隐藏弹出窗口的方法。干杯人..
  • @Sheridan 我有一个疑问。我已经处理了 ScrollChanged 事件,但是这个事件处理程序被多次调用,从而导致进程出现一些延迟。我做错了吗?
【解决方案2】:

查看this question here,其中讨论了确定对象在 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...
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-21
    • 1970-01-01
    • 2015-08-09
    • 1970-01-01
    • 1970-01-01
    • 2019-03-10
    • 1970-01-01
    相关资源
    最近更新 更多