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

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

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

Ответ 1

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

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

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

ScrollViewer.CanContentScroll="False"

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

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

Ответ 2

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

Обычно в WPF ScrollViewer использует так называемую логическую прокрутку, что означает, что она будет перемещаться по элементу по позиции вместо суммы смещения. Другие ответы охватывают некоторые способы изменения поведения логической прокрутки по сравнению с физическим прокруткой. Другой способ - использовать методы ScrollToVertialOffset и ScrollToHorizontalOffset, представленные как 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 или что-то подобное.

Ответ 3

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

Ответ 4

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

Ответ 5

попробуйте установить высоту списка в виде авто и обернуть ее в средстве просмотра прокрутки.

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

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