Отрегулировать приращение прокрутки FlowDocumentReader, когда режим просмотра установлен на прокрутку? - PullRequest
6 голосов
/ 18 мая 2009

Я отображаю FlowDocument в FlowDocumentReader с помощью PreviewMode = "Scroll". Если я использую колесо на моей мыши, документ прокручивается очень медленно. Я хотел бы увеличить шаг прокрутки.

  1. Я пытался изменить настройку прокрутки мыши на панели управления, но это не имеет никакого эффекта. Я думаю, что WPF игнорирует этот параметр для FlowDocumentScrollViewer.

  2. Я добавил событие Scroll в FlowDocument и FlowDocumentReader, но оно не срабатывает, когда я использую колесо мыши.

  3. Я добавил событие Loaded в FlowDocumentReader, получил потомка ScrollViewer, нашел ScrollBar ("PART_VerticalScrollBar") из шаблона средства просмотра с прокруткой и отрегулировал свойства SmallChange & LargeChange. Это также не имело никакого эффекта.

У кого-нибудь есть идеи?

Ответы [ 3 ]

20 голосов
/ 10 июня 2009

Мы можем изменить это в событии MouseWheel элемента управления, например, Sohnee sugested, но тогда оно будет решено только для одного конкретного случая, и вам потребуется доступ к FlowDocumentReader, который, если вы используете что-то вроде MVVM, ты не будешь. Вместо этого мы можем создать вложенное свойство, которое затем можем установить для любого элемента с помощью ScrollViewer. При определении нашего присоединенного свойства мы также хотим получить обратный вызов PropertyChanged, в котором мы будем выполнять фактические изменения скорости прокрутки. Я также присвоил своему свойству значение по умолчанию 1, диапазон скоростей, который я собираюсь использовать, составляет от 0,1 до 3 раз, хотя вы могли бы так же легко сделать что-то вроде 1-10.

public static double GetScrollSpeed(DependencyObject obj)
{
    return (double)obj.GetValue(ScrollSpeedProperty);
}

public static void SetScrollSpeed(DependencyObject obj, double value)
{
    obj.SetValue(ScrollSpeedProperty, value);
}

public static readonly DependencyProperty ScrollSpeedProperty =
    DependencyProperty.RegisterAttached(
    "ScrollSpeed",
    typeof(double),
    typeof(ScrollHelper),
    new FrameworkPropertyMetadata(
        1.0,
        FrameworkPropertyMetadataOptions.Inherits & FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
        new PropertyChangedCallback(OnScrollSpeedChanged)));

private static void OnScrollSpeedChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
}

Теперь, когда у нас есть свойство Attached, нам нужно обработать прокрутку, для этого в OnScrollSpeedChanged мы можем обработать событие PreviewMouseWheel. Мы хотим подключиться к PreviewMouseWheel, поскольку это событие туннелирования, которое произойдет до того, как ScrollViewer сможет обработать стандартное событие MouseWheel.

В настоящее время обработчик PreviewMouseWheel принимает FlowDocumentReader или другую вещь, с которой мы его связываем, однако нам нужен ScrollViewer. Поскольку это может быть много вещей: ListBox, FlowDocumentReader, WPF Toolkit Grid, ScrollViewer и т. Д., Мы можем сделать короткий метод, который использует VisualTreeHelper для этого. Мы уже знаем, что проходящий элемент будет некой формой DependancyObject, поэтому мы можем использовать некоторую рекурсию, чтобы найти ScrollViewer, если он существует.

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;
}

private static void OnScrollSpeedChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
    var host = o as UIElement;
    host.PreviewMouseWheel += new MouseWheelEventHandler(OnPreviewMouseWheelScrolled);
}

Теперь, когда мы можем получить ScrollViwer, мы можем, наконец, изменить скорость прокрутки. Нам нужно получить свойство ScrollSpeed ​​из объекта DependancyObject, который отправляется через. Также мы можем использовать наш вспомогательный метод, чтобы получить ScrollViewer, который содержится внутри элемента. Получив эти две вещи, мы можем получить и изменить VerticalOffset ScrollViewer. Я обнаружил, что при делении MouseWheelEventArgs.Delta, который является величиной, на которую изменилось колесо мыши, на 6 получается примерно скорость прокрутки по умолчанию. Итак, если мы умножим это на наш модификатор ScrollSpeed, мы сможем получить новое значение смещения. Затем мы можем установить ScrollViewer VerticalOffset, используя метод ScrollToVerticalOffset, который он предоставляет.

private static void OnPreviewMouseWheelScrolled(object sender, MouseWheelEventArgs e)
{
    DependencyObject scrollHost = sender as DependencyObject;

    double scrollSpeed = (double)(scrollHost).GetValue(Demo.ScrollSpeedProperty);

    ScrollViewer scrollViewer = GetScrollViewer(scrollHost) as ScrollViewer;

    if (scrollViewer != null)
    {
        double offset = scrollViewer.VerticalOffset - (e.Delta * scrollSpeed / 6);
        if (offset < 0)
        {
            scrollViewer.ScrollToVerticalOffset(0);
        }
        else if (offset > scrollViewer.ExtentHeight)
        {
            scrollViewer.ScrollToVerticalOffset(scrollViewer.ExtentHeight);
        }
        else
        {
            scrollViewer.ScrollToVerticalOffset(offset);
        }

        e.Handled = true;
    }
    else
    {
        throw new NotSupportedException("ScrollSpeed Attached Property is not attached to an element containing a ScrollViewer.");
    }
}

Теперь, когда мы настроили наше Присоединенное свойство, мы можем создать простой интерфейс для его демонстрации. Я собираюсь создать ListBox и FlowDocumentReaders, чтобы мы могли видеть, как ScrollSpeed ​​будет затронут несколькими элементами управления.

<UniformGrid Columns="2">
    <DockPanel>
        <Slider DockPanel.Dock="Top"
            Minimum=".1"
            Maximum="3"
            SmallChange=".1"
            Value="{Binding ElementName=uiListBox, Path=(ScrollHelper:Demo.ScrollSpeed)}" />
        <ListBox x:Name="uiListBox">
            <!-- Items -->
        </ListBox>
    </DockPanel>
    <DockPanel>
        <Slider DockPanel.Dock="Top"
            Minimum=".1"
            Maximum="3"
            SmallChange=".1"
            Value="{Binding ElementName=uiListBox, Path=(ScrollHelper:Demo.ScrollSpeed)}" />
        <FlowDocumentReader x:Name="uiReader"
            ViewingMode="Scroll">
            <!-- Flow Document Content -->
        </FlowDocumentReader>
    </DockPanel>
</UniformGrid>

Теперь при запуске мы можем использовать ползунки, чтобы изменять скорость прокрутки в каждом из столбцов, забавные вещи.

0 голосов
/ 24 апреля 2018

Ничего себе. Ответ Rmoore блестящий, но немного сложный. Я немного упростил это. Для тех, кто не использует MVVM или может разместить код внутри класса, который имеет доступ к целевому элементу, вам хватит этих двух методов:

Поместите этот метод в ваши расширения:

   public static DependencyObject GetScrollViewer(this 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;
        }

Затем поместите второй метод в класс, который имеет доступ к целевому элементу пользовательского интерфейса, и подпишите его на событие «PreviewMouseWheel»

     private void HandleScrollSpeed(object sender, MouseWheelEventArgs e)
        {
            try
            {
                if (!(sender is DependencyObject))
                    return;

                ScrollViewer scrollViewer = (((DependencyObject)sender)).GetScrollViewer() as ScrollViewer;
                ListBox lbHost = sender as ListBox; //Or whatever your UI element is

                if (scrollViewer != null && lbHost != null)
                {
                    double scrollSpeed = 1;
    //you may check here your own conditions
                    if (lbHost.Name == "SourceListBox" || lbHost.Name == "TargetListBox")
                        scrollSpeed = 2;

                    double offset = scrollViewer.VerticalOffset - (e.Delta * scrollSpeed / 6);
                    if (offset < 0)
                        scrollViewer.ScrollToVerticalOffset(0);
                    else if (offset > scrollViewer.ExtentHeight)
                        scrollViewer.ScrollToVerticalOffset(scrollViewer.ExtentHeight);
                    else
                        scrollViewer.ScrollToVerticalOffset(offset);

                    e.Handled = true;
                }
                else
                    throw new NotSupportedException("ScrollSpeed Attached Property is not attached to an element containing a ScrollViewer.");
            }
            catch (Exception ex)
            {
//Do something...
            }
        }
0 голосов
/ 09 июня 2009

Вместо использования события прокрутки захватите событие MouseWheel.

<FlowDocumentReader MouseWheel="...">
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...