Можно ли реализовать плавную прокрутку в просмотре списка WPF?

Можно ли реализовать плавную прокрутку в WPF listview например, как это работает в Firefox?
Когда браузер Firefox содержал все listview элементы и удерживая среднюю кнопку мыши (но не отпустить), и перетащите его, он должен плавно прокручивать listview Предметы. Когда вы отпустите, он должен остановиться.

Похоже, что это невозможно в winforms, но мне интересно, если это доступно в WPF?

6 ответов

Вы можете добиться плавной прокрутки, но вы потеряете виртуализацию элементов, поэтому в основном вы должны использовать эту технику, только если у вас есть несколько элементов в списке:

Информация здесь: Плавная прокрутка в списке

Вы пробовали установить:

ScrollViewer.CanContentScroll="False"

в окне списка?

Таким образом, прокрутка обрабатывается панелью, а не списком... Вы теряете виртуализацию, если делаете это, хотя это может быть медленнее, если у вас много контента.

Я знаю, что этому посту 13 лет, но люди все еще хотят это сделать. в более новых версиях .Net вы можете установить VirtualizingPanel.ScrollUnit="Pixel"таким образом, вы не потеряете виртуализацию и получите прокрутку на пиксель, а не на элемент.

Это действительно возможно сделать то, что вы просите, хотя это потребует значительного количества пользовательского кода.

Обычно в WPF ScrollViewer использует так называемую логическую прокрутку, что означает, что он будет прокручивать элемент по элементу, а не по величине смещения. Другие ответы охватывают некоторые способы изменения поведения логической прокрутки на физическую прокрутку. Другой способ заключается в использовании методов ScrollToVertialOffset и ScrollToHorizontOffset, предоставляемых как ScrollViwer, так и IScrollInfo.

Чтобы реализовать большую часть, прокрутку при нажатии колесика мыши, нам нужно будет использовать события MouseDown и MouseMove.

<ListView x:Name="uiListView"
          Mouse.MouseDown="OnListViewMouseDown"
          Mouse.MouseMove="OnListViewMouseMove"
          ScrollViewer.CanContentScroll="False">
    ....
</ListView>

В MouseDown мы собираемся записать текущее положение мыши, которое мы будем использовать в качестве относительной точки, чтобы определить направление прокрутки. При перемещении мыши мы получим компонент ScrollViwer объекта ListView и затем прокрутите его. соответственно.

private Point myMousePlacementPoint;

private void OnListViewMouseDown(object sender, MouseButtonEventArgs e)
{
    if (e.MiddleButton == MouseButtonState.Pressed)
    {
        myMousePlacementPoint = this.PointToScreen(Mouse.GetPosition(this));
    }
}

private void OnListViewMouseMove(object sender, MouseEventArgs e)
{
    ScrollViewer scrollViewer = ScrollHelper.GetScrollViewer(uiListView) as ScrollViewer;

    if (e.MiddleButton == MouseButtonState.Pressed)
    {
        var currentPoint = this.PointToScreen(Mouse.GetPosition(this));

        if (currentPoint.Y < myMousePlacementPoint.Y)
        {
            scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - 3);
        }
        else if (currentPoint.Y > myMousePlacementPoint.Y)
        {
            scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + 3);
        }

        if (currentPoint.X < myMousePlacementPoint.X)
        {
            scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset - 3);
        }
        else if (currentPoint.X > myMousePlacementPoint.X)
        {
            scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset + 3);
        }
    }
}

public static DependencyObject GetScrollViewer(DependencyObject o)
{
    // Return the DependencyObject if it is a ScrollViewer
    if (o is ScrollViewer)
    { return o; }

    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
    {
        var child = VisualTreeHelper.GetChild(o, i);

        var result = GetScrollViewer(child);
        if (result == null)
        {
            continue;
        }
        else
        {
            return result;
        }
    }
    return null;
}

Есть некоторые области, которых ему не хватает, так как это просто доказательство концепции, но это определенно должно привести вас в правильном направлении. Чтобы она постоянно прокручивалась после перемещения мыши от начальной точки MouseDown, логика прокрутки может переходить в DispatcherTimer или что-то подобное.

Попробуйте установить для присоединенного свойства ScrollViewer.CanContentScroll значение false в ListView. Но, как сказал Pop Catalin, вы теряете виртуализацию элементов, то есть все элементы в списке загружаются и заполняются одновременно, а не тогда, когда необходимо отобразить набор элементов - поэтому, если список огромен, это может привести к некоторой памяти и проблемы с производительностью.

Если вы используете.NET 4.5 (или 4.0, если хотите немного взломать), здесь есть ответ.

Попробуйте установить высоту списка в качестве автоматического и обернуть его в просмотрщик прокрутки.

<ScrollViewer IsTabStop="True" VerticalScrollBarVisibility="Auto">
     <ListView></ListView>
</ScrollViewer>

Не забудьте упомянуть высоту ScrollViewer Надеюсь, это поможет....

Другие вопросы по тегам