Записывать элементы, видимые пользователю в ListBox

У меня есть ListBox или DataGrid, заполненный тысячами записей. Я хотел бы знать элементы, которые пользователь просматривал (прокрутка, поиск и т. Д.). Как узнать, что видит пользователь в ListBox?

Бонус: установите таймер, чтобы элемент отображался не менее N миллисекунд (в случае, если пользователь просто опускает полосу прокрутки).

Обновление: это почти дубликат Получить элементы в представление в списке, но предлагаемого решения с использованием "SelectedItems" недостаточно. Мне нужно знать, выбраны они или нет!


person tofutim    schedule 27.05.2011    source источник
comment
Это может быть еще одна подсказка: stackoverflow.com/questions/610343/   -  person tofutim    schedule 29.05.2011
comment
Разъяснения, которые я хотел бы знать: что это такое? ListBox или DataGrid? Или вы собираетесь выбрать одно из двух в зависимости от того, возможно ли решение с одним, а не с другим? Если вы используете ListBox, меняете ли вы его свойство ItemsPanel?   -  person Joel B Fant    schedule 30.05.2011
comment
Я использую сетку данных Xceed, но я хочу использовать для этого обычную сетку данных или список.   -  person tofutim    schedule 30.05.2011
comment
Может быть, это? xceed.com/CS/forums/thread/11126.aspx   -  person tofutim    schedule 30.05.2011
comment
Поскольку вы назначили награду за это и отметили ответ Элада как принятый, вам, вероятно, следует наградить его наградой. В настоящее время это не произойдет автоматически по окончании окна награды.   -  person Joel B Fant    schedule 02.06.2011


Ответы (1)


Все, что вам нужно сделать, это получить базовый StackPanel, который находится внутри ListBox. В нем достаточно информации о том, какие элементы отображаются. (Реализует интерфейс IScrollInfo).

Чтобы получить базовый StackPanel (или фактически VirtualizingStackPanel) из данного ListBox, нам нужно будет использовать VisualTreeHelper для просмотра визуального дерева и поиска VirtualizingStackPanel, например:

    private VirtualizingStackPanel GetInnerStackPanel(FrameworkElement element)
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
        {
            var child = VisualTreeHelper.GetChild(element, i) as FrameworkElement;

            if (child == null) continue;

            Debug.WriteLine(child.ToString());

            if (child is VirtualizingStackPanel) return child as VirtualizingStackPanel;

            var panel = GetInnerStackPanel(child);

            if (panel != null)
                return panel;
        }

        return null;

    }

Теперь, когда у нас есть StackPanel, мы очень близки. StackPanel имеет свойства VerticalOffset и ViewportHeight (оба взяты из IScrollInfo), которые могут предоставить нам всю необходимую информацию.

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        var theStackPanel = GetInnerStackPanel(MyListBox);

        List<FrameworkElement> visibleElements = new List<FrameworkElement>();

        for (int i = 0; i < theStackPanel.Children.Count; i++)
        {

            if (i >= theStackPanel.VerticalOffset && i <= theStackPanel.VerticalOffset + theStackPanel.ViewportHeight)
            {
                visibleElements.Add(theStackPanel.Children[i] as FrameworkElement);
            }
        }


        MessageBox.Show(visibleElements.Count.ToString());
        MessageBox.Show(theStackPanel.VerticalOffset.ToString());
        MessageBox.Show((theStackPanel.VerticalOffset + theStackPanel.ViewportHeight).ToString());

    }
person Elad Katz    schedule 30.05.2011