0

I've a WrapPanel surrounded with a ScrollViewer, I want to find the visible elements on the screen when I click a button.

My code like:

<ScrollViewer>
    <WrapPanel>
        <Label Width="500" Height="500"/>
        <Label Width="500" Height="500"/>
        <Label Width="500" Height="500"/>
        ....
        ....
        ....
        <Label Width="500" Height="500"/>
        <Label Width="500" Height="500"/>
        <Label Width="500" Height="500"/>
    </WrapPanel>
</ScrollPanel>

How can I find the visible Label elements when ScrollViewer scrolled to some offset.

cKNet
  • 635
  • 1
  • 10
  • 22

1 Answers1

0

Hopefully this will get you started (you may want to change 'svViewportBounds.IntersectsWith' with 'Contains'.

public partial class MainWindow : Window
{
    public string VisibleItems
    {
        get { return (string)GetValue(VisibleItemsProperty); }
        set { SetValue(VisibleItemsProperty, value); }
    }

    public static readonly DependencyProperty VisibleItemsProperty =
        DependencyProperty.Register("VisibleItems", typeof(string), typeof(MainWindow), new PropertyMetadata("??"));

    public List<string> Items { get; private set; }

    public MainWindow()
    {
        Items = new List<string>();

        for (int i = 0; i < 25; ++i )
        {
            Items.Add("item_" + i);
        }

        DataContext = this;
        InitializeComponent();
    }

    void OnScrollViewerScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        ScrollViewer sv = (ScrollViewer)sender;
        var visibleItems = new List<int>();
        Rect svViewportBounds = new Rect(sv.HorizontalOffset, sv.VerticalOffset, sv.ViewportWidth, sv.ViewportHeight);

        for(int i = 0; i < Items.Count; ++i)
        {
            var container = itemsHost.ItemContainerGenerator.ContainerFromIndex(i) as FrameworkElement;
            if(container != null)
            {
                var offset = VisualTreeHelper.GetOffset(container);
                var bounds = new Rect(offset.X, offset.Y, container.ActualWidth, container.ActualHeight);

                if (svViewportBounds.IntersectsWith(bounds))
                {
                    visibleItems.Add(i);
                }
            }
        }

        VisibleItems = string.Join(", ", visibleItems.ToArray());
    }
}

<Window x:Class="WpfApplication59.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow"
    WindowStartupLocation="CenterScreen"
    Width="400"
    Height="400">
<DockPanel>
    <Border BorderThickness="1"
            BorderBrush="Black"
            DockPanel.Dock="Top">
        <TextBlock Text="{Binding VisibleItems}"
                   Margin="5" />
    </Border>

    <ItemsControl ItemsSource="{Binding Items}" Name="itemsHost">
        <ItemsControl.Template>
            <ControlTemplate>
                <ScrollViewer HorizontalScrollBarVisibility="Disabled"
                              ScrollChanged="OnScrollViewerScrollChanged">
                    <WrapPanel IsItemsHost="True" />
                </ScrollViewer>
            </ControlTemplate>
        </ItemsControl.Template>

        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Border BorderThickness="1"
                        BorderBrush="Black"
                        Width="100"
                        Height="100">
                    <Label Content="{Binding}" />
                </Border>
            </DataTemplate>
        </ItemsControl.ItemTemplate>

        <ItemsControl.ItemContainerStyle>
            <Style TargetType="{x:Type ContentPresenter}">
                <Setter Property="Margin"
                        Value="4" />
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>
</DockPanel>

pastillman
  • 1,104
  • 2
  • 16
  • 27