【问题标题】:How to enable horizontal scrolling with mouse?如何使用鼠标启用水平滚动?
【发布时间】:2010-09-16 14:03:07
【问题描述】:

我无法确定如何使用鼠标滚轮进行水平滚动。垂直滚动自动运行良好,但我需要水平滚动我的内容。我的代码如下所示:

<ListBox x:Name="receiptList"
         Margin="5,0"
         Grid.Row="1"
         ItemTemplate="{StaticResource receiptListItemDataTemplate}"
         ItemsSource="{Binding OpenReceipts}"
         ScrollViewer.VerticalScrollBarVisibility="Disabled">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"
                        ScrollViewer.HorizontalScrollBarVisibility="Visible"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ListBox>

我的项目模板如下所示:

<DataTemplate x:Key="receiptListItemDataTemplate">
    <RadioButton GroupName="Numbers"
                 Command="{Binding Path=DataContext.SelectReceiptCommand,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type POS:PointOfSaleControl}}}"
                 CommandParameter="{Binding }"
                 Margin="2,0"
                 IsChecked="{Binding IsSelected}">
        <RadioButton.Template>
            <ControlTemplate TargetType="{x:Type RadioButton}" >
                <Grid x:Name="receiptGrid" >
                    <Grid>
                        <Border BorderThickness="2" 
                                BorderBrush="Green" 
                                Height="20" 
                                Width="20">
                            <Grid x:Name="radioButtonGrid" 
                                  Background="DarkOrange">
                                <TextBlock x:Name="receiptLabel"
                                           HorizontalAlignment="Center"
                                           VerticalAlignment="Center"
                                           Text="{Binding Path=NumberInQueue, Mode=OneWay}"
                                           FontWeight="Bold"
                                           FontSize="12"
                                           Foreground="White">
                                </TextBlock>
                            </Grid>
                        </Border>
                    </Grid>
                </Grid>

                <ControlTemplate.Triggers>
                    <Trigger Property="IsChecked" Value="True">
                        <Setter Property="Margin" 
                                TargetName="receiptGrid" 
                                Value="2,2,-1,-1"/>
                        <Setter Property="Background"
                                TargetName="radioButtonGrid" 
                                Value="Maroon"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </RadioButton.Template>
    </RadioButton>          
</DataTemplate>

是否需要添加其他方法或控件才能获得该功能?

【问题讨论】:

  • 您应该在您的问题中明确(通过重新表述)您需要一个鼠标滚轮工作的解决方案。像我这样的人不容易做到。

标签: wpf scrollviewer horizontal-scrolling


【解决方案1】:

这是一个完整的行为。将以下类添加到您的代码中,然后在您的 XAML 中将任何包含 ScrollViewer 作为可视子项的 UIElement 上的附加属性设置为 true。

<MyVisual ScrollViewerHelper.ShiftWheelScrollsHorizontally="True" />

班级:

public static class ScrollViewerHelper
{
    public static readonly DependencyProperty ShiftWheelScrollsHorizontallyProperty
        = DependencyProperty.RegisterAttached("ShiftWheelScrollsHorizontally",
            typeof(bool),
            typeof(ScrollViewerHelper),
            new PropertyMetadata(false, UseHorizontalScrollingChangedCallback));

    private static void UseHorizontalScrollingChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var element = d as UIElement;

        if (element == null)
            throw new Exception("Attached property must be used with UIElement.");

        if ((bool)e.NewValue)
            element.PreviewMouseWheel += OnPreviewMouseWheel;
        else
            element.PreviewMouseWheel -= OnPreviewMouseWheel;
    }

    private static void OnPreviewMouseWheel(object sender, MouseWheelEventArgs args)
    {
        var scrollViewer = ((UIElement)sender).FindDescendant<ScrollViewer>();

        if (scrollViewer == null)
            return;

        if (Keyboard.Modifiers != ModifierKeys.Shift)
            return;

        if (args.Delta < 0)
            scrollViewer.LineRight();
        else
            scrollViewer.LineLeft();

        args.Handled = true;
    }

    public static void SetShiftWheelScrollsHorizontally(UIElement element, bool value) => element.SetValue(ShiftWheelScrollsHorizontallyProperty, value);
    public static bool GetShiftWheelScrollsHorizontally(UIElement element) => (bool)element.GetValue(ShiftWheelScrollsHorizontallyProperty);

    [CanBeNull]
    private static T FindDescendant<T>([CanBeNull] this DependencyObject d) where T : DependencyObject
    {
        if (d == null)
            return null;

        var childCount = VisualTreeHelper.GetChildrenCount(d);

        for (var i = 0; i < childCount; i++)
        {
            var child = VisualTreeHelper.GetChild(d, i);

            var result = child as T ?? FindDescendant<T>(child);

            if (result != null)
                return result;
        }

        return null;
    }
}

此答案修复了Johannes' answer 中的一些错误,例如未按 Shift 键过滤、同时水平和垂直滚动(运动是对角线)以及无法通过将属性设置为 false 来禁用该行为。

【讨论】:

  • 不编译。找不到类及其属性,这是 XAML 文件中的三个错误。 C# 文件没有自己的错误。 VS2015
  • @ygoe,您需要设置一个映射到该类的 CLR 命名空间的 xmlns。
  • 我已将该类放入我自己的命名空间中,并且已经使用了那里的其他类。这不是问题。
  • @ygoe 你得到什么错误?这个确切的代码可以在我的电脑上运行。
  • Property not found 问题是由 Get 和 Set 属性的错误名称引起的。它们需要是 SetShiftWheelScrollsHorizontallyGetShiftWheelScrollsHorizontally 而不是 SetUseHorizontalScrollingGetUseHorizontalScrolling
【解决方案2】:

为此,我写了一个Attached Property,以便在每个包含ScrollViewer 的ItemsControl 上重用它。 FindChildByType 是 Telerik 扩展,但也可以找到 here

 public static readonly DependencyProperty UseHorizontalScrollingProperty = DependencyProperty.RegisterAttached(
            "UseHorizontalScrolling", typeof(bool), typeof(ScrollViewerHelper), new PropertyMetadata(default(bool), UseHorizontalScrollingChangedCallback));

        private static void UseHorizontalScrollingChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
        {
            ItemsControl itemsControl = dependencyObject as ItemsControl;

            if (itemsControl == null) throw new ArgumentException("Element is not an ItemsControl");

            itemsControl.PreviewMouseWheel += delegate(object sender, MouseWheelEventArgs args)
            {
                ScrollViewer scrollViewer = itemsControl.FindChildByType<ScrollViewer>();

                if (scrollViewer == null) return;

                if (args.Delta < 0)
                {
                    scrollViewer.LineRight();
                }
                else
                {
                    scrollViewer.LineLeft();
                }
            };
        }


        public static void SetUseHorizontalScrolling(ItemsControl element, bool value)
        {
            element.SetValue(UseHorizontalScrollingProperty, value);
        }

        public static bool GetUseHorizontalScrolling(ItemsControl element)
        {
            return (bool)element.GetValue(UseHorizontalScrollingProperty);
        }

【讨论】:

  • 这应该是公认的答案,+1 用于包含代码和指向获取更多代码的位置的链接。这个实现在第一次尝试时就奏效了,并且非常简单地将行为添加到我想要添加到的控件中。
【解决方案3】:

最简单的方法是将PreviewMouseWheel 监听器添加到ScrollViewer,检查移位(或任何你想做的指示水平滚动),然后调用LineLeftLineRight(或PageLeft /PageRight) 取决于Delta的值MouseWheelEventArgs的值

【讨论】:

  • 我不明白这个答案:当根本没有 ScrollViewer 时,我应该如何添加 PreviewMouseWheel?
  • 我相信列表框的控件模板里面有一个滚动查看器。因此像ScrollViewer.VerticalScrollBarVisibility="Disabled" 这样的附加属性起作用的原因。
  • 是的,但这些是附加属性。但是如何在不重写控件模板的情况下附加 ScrollViewer 的 PreviewMouseWheel(我不会这样做,因为这会破坏依赖于操作系统的自动主题)?
  • 我想你会在可视化树中找到它吗? (不记得了,这个答案现在已经 3 岁了 :))
【解决方案4】:

我有点想寻找最简单的方法来让任何ScrollViewer 左右滚动而不是上下滚动。所以这是其他答案的最简单组合。

<ScrollViewer HorizontalScrollBarVisibility="Visible"
              PreviewMouseWheel="ScrollViewer_PreviewMouseWheel"> 

和:

private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
    ScrollViewer scrollViewer = (ScrollViewer)sender;
    if (e.Delta < 0)
    {
        scrollViewer.LineRight();
    }
    else
    {
        scrollViewer.LineLeft();
    }
    e.Handled = true;
}

这基本上就是John Gardner suggested 的实际代码。我还引用了similar question here 的回答。

【讨论】:

    【解决方案5】:
    (sender as ScrollViewer).ScrollToHorizontalOffset( (sender as ScrollViewer).ContentHorizontalOffset    + e.Delta);
    

    【讨论】:

    • 我使用了这个,但必须减去 delta 值才能获得预期的行为(即当鼠标滚轮向下/朝向用户时内容向右滚动)。
    【解决方案6】:

    试试这个:

    <ListBox x:Name="receiptList" 
                           Margin="5,0" 
                           Grid.Row="1" 
                           ItemTemplate="{StaticResource receiptListItemDataTemplate}" 
                           ItemsSource="{Binding OpenReceipts}" 
                           ScrollViewer.VerticalScrollBarVisibility="Disabled" 
                           ScrollViewer.HorizontalScrollBarVisibility="Visible"
                               > 
                    <ItemsControl.ItemsPanel> 
                      <ItemsPanelTemplate> 
                        <StackPanel Orientation="Horizontal" /> 
                      </ItemsPanelTemplate> 
                    </ItemsControl.ItemsPanel> 
    </ListBox> 
    

    更新 糟糕,错过了关于鼠标滚轮的部分!对不起

    要使鼠标滚轮工作,您必须订阅鼠标滚轮事件并手动移动滚动条...这可以很好地封装在一个行为中,但我认为这是使它工作的唯一方法!

    【讨论】:

    • 这不起作用。它仅适用于键盘“->”和“
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-26
    • 1970-01-01
    • 2018-12-30
    • 2021-10-09
    • 2013-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多