0

Мне необходимо контролировать прокрутку DataGrid, т.е. решать какой элемент должен быть верхним отображаемым. Для этого я хочу использовать либо свойство CurrentItem либо метод ScrollIntoView(). Но все упирается в то, что я не могу получить индекс верхней строки. Есть ли какой-то вариант получить этот индекс?

  • А если перематывать в два этапа: сначала перематываем на самый первый, потом на нужный. Он не будет верхним в таком случае? (перематывать с помощью ScrollIntoView, да) – Андрей NOP Aug 28 '18 at 05:37
  • @АндрейNOP Идея в принципе интересная, но не будет ли прыжков? И все равно, самым интересным является именно определение "нужного" элемента. Мне ведь надо понять на каком элементе сейчас пользователь. Вот крутит он колесом или скролбаром и текущий верхний отображаемый элемент мне и нужен. – Ivan Kozlov Aug 28 '18 at 05:41
  • а можно развить вашу мысль по поводу того зачем вам нужен верхний элемент, возможно вам подскажут, как по другому это сделать? А вообще пока, я бы начал двигаться в сторону того что высчитал часть прокрученного и разбивку по страницам, и математикой подтянул бы номер строки которая верхняя, но это в теории на практике я бы поискал иной путь. – Monomax Aug 28 '18 at 05:48
  • у меня есть таблица, в которую подтягиваются сообщения из БД в режиме реального времени. Иногда пользователю потребуется посмотреть сообщения, которые приходили ранее, так вот чтобы при приходе нового сообщения пользователя не дергало вверх мне и нужно знать номер верхнего отображаемого сообщения. При приходе нового я просто перемотаю грид до нужного мне( верхнего отображаемого) индекса и пользователь ничего не заметит – Ivan Kozlov Aug 28 '18 at 05:51
  • @Monomax, а как вообще можно высчитать прокрученное? Я не могу найти события прокрутки в DataGrid. – Ivan Kozlov Aug 28 '18 at 05:53
  • Эмм, а зачем вы вообще перематываете при приходе нового элемента? Подозреваю, что вы полностью ItemsSource меняете у DataGrid? Не нужно этого делать, просто догружайте в уже привязанную коллекцию – Андрей NOP Aug 28 '18 at 05:54
  • @АндрейNOP, по умолчанию, DataGrid сдвигает строку на 1 вниз при приходе нового элемента. У меня же при приходе элемента, с помощью ScrollIntoView весь грид отматывается наверх. Это необходимо по ТЗ. Типа видишь новые события. Весь вопрос во втором режиме. Когда пользователь просматривает то, что было раньше. – Ivan Kozlov Aug 28 '18 at 05:57
  • Ну дык не отматывайте во втором режиме, пока не понятно – Андрей NOP Aug 28 '18 at 05:58
  • @АндрейNOP, во втором режиме и не мотаю. Новые элементы добавляются сверху таблицы. при добавлении элемента происходит смещение всех элементов на 1 вниз. Вот это не есть правильно. Правильно, чтобы все стояло на месте – Ivan Kozlov Aug 28 '18 at 06:02
  • @АндрейNOP, а каким образом обновить отображение в гриде кроме обновления ItemSource? – Ivan Kozlov Aug 28 '18 at 06:03
  • а каким образом обновить отображение в гриде кроме обновления ItemSource? — например, с помощью ObservableCollection // Ок, теперь понятно, попробую что-то сочинить – Андрей NOP Aug 28 '18 at 06:04
  • @АндрейNOP, ObservableCollection не перестраивает грид. Кроме явного изменения ItemSource я не могу придумать вариантов – Ivan Kozlov Aug 28 '18 at 06:33
  • Значит вы что-то неправильно делаете, т.к. именно для этих целей ObservableCollection и сделан (реализация INotifyCollectionChanged) – Андрей NOP Aug 28 '18 at 06:45
  • Задание источника данных для грида:ItemsSource="{Binding Path=(local:Messages.MessagesCollection), UpdateSourceTrigger=PropertyChanged}" и само свойство: public static ObservableCollection<Message> MessagesCollection { get { return messages; } set { messages = value; } } – Ivan Kozlov Aug 28 '18 at 06:47
  • Ну а добавляете элементы вы в ObservableCollection как? – Андрей NOP Aug 28 '18 at 06:54
  • С добавлением новых элементов проблем нет. Проблема с обновлением уже имеющихся элементов. У меня в гриде шаблон ячейки завязан на ее значение. По умолчанию в ячейке кнопка, а при нажатии вместо кнопки отображается TextBlock со временем нажатия. Вот без обновления ItemSource шаблон не меняется – Ivan Kozlov Aug 28 '18 at 06:59
  • А, ну дык ваши Message должны реализовывать INotifyPropertyChanged. "Классический" пример на этом сайте: https://ru.stackoverflow.com/a/573196/218063 Обратите внимание, стрелочки поворачиваются без переназначения ItemsSource – Андрей NOP Aug 28 '18 at 07:10
  • @АндрейNOP, Благодарю за помощь! – Ivan Kozlov Aug 28 '18 at 07:18

1 Answers1

3

Получите ScrollViewer вашего DataGrid:

public MainWindow()
{
    InitializeComponent();
    Loaded += (o, e) => scrollViewer = GetVisualChild<ScrollViewer>(MyDataGrid);
}

ScrollViewer scrollViewer;

private static T GetVisualChild<T>(DependencyObject parent) where T : Visual
{
    T child = null;
    int count = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < count; i++)
    {
        var v = (Visual)VisualTreeHelper.GetChild(parent, i);
        child = v as T;
        if (child == null) child = GetVisualChild<T>(v);
        if (child != null) break;
    }
    return child;
}

Что интересно, ScrollViewer внутри DataGrid отсчитывает вертикальное смещение в элементах, а не в координатах (как он обычно это делает).

Перед добавлением новых элементов запомните текущее смещение:

int verticalOffset;

verticalOffset = (int)scrollViewer.VerticalOffset;

А после добавления скорректируйте его (здесь x — количество добавленных элементов):

scrollViewer.ScrollToVerticalOffset(verticalOffset + x);

введите сюда описание изображения