【问题标题】:Listview inside of scrollviewer prevents scrollviewer scrollscrollviewer 内的 Listview 防止 scrollviewer 滚动
【发布时间】:2012-01-19 20:21:51
【问题描述】:

我有一个滚动查看器,里面有几个列表框。问题是如果用户在鼠标悬停在列表视图上时使用鼠标中键滚动滚动查看器。 listview 将其内部的 scrollviewer 滚动到底部,然后继续捕获鼠标,从而阻止包含的 scrollviewer 滚动。

关于如何处理这个问题的任何想法?

【问题讨论】:

标签: c# wpf listbox scrollviewer


【解决方案1】:

发生这种情况是因为ListView(实际上是ListBox)内容模板使用ScrollViewer 自己包装了它的项目。

最简单的方法是通过将您自己的Template 删除为内部ListView(不会创建ScrollViewer)来禁用它:

    <ListView>
      <ListView.Template>
        <ControlTemplate>
          <ItemsPresenter></ItemsPresenter>
        </ControlTemplate>
      </ListView.Template>
      ...
    </ListView>

顺便说一句,如果您在 ListView 中有一个 ListView(这是我的情况),也会发生同样的情况。

【讨论】:

  • 这个解决方案对我来说效果很好,而且很容易实现。我尝试了其他建议的解决方案,但只有这对我有用(ScrollViewer 中的 ListViewer)
  • 我正在寻找这个。 Windows 10 开发已经很长时间了,这个问题在 WPF 中让我感到惊讶。谢谢+1 :)
  • 哈哈谢谢!自 2013 年以来我没有接触过任何 C#,很高兴看到这个答案仍然相关!
【解决方案2】:

您是否尝试禁用 ListView's ScrollBars

<ListView ScrollViewer.HorizontalScrollBarVisibility="Disabled"
          ScrollViewer.VerticalScrollBarVisibility="Disabled" />

【讨论】:

  • 我不能这样做,因为列表视图中的项目可能比可见的要多。
  • @Justin984 他们不是在另一个ScrollViewer吗?
  • 呸,我本来打算画一点 ascii 图片,但是太痛苦了。每个列表框都有多个条目。例如,列表框 1 可能有 10 个条目,需要滚动列表框才能查看。但是有多个列表框一起对于屏幕来说太大了,所以我有一个外部滚动查看器来滚动列表框进入视图。这有意义吗?
  • @Justin984 也许您可以做一些事情,如果 ListView 已经滚动到底部,它会停止响应向下滚动事件?还是将它们传递给外部ScrollViewer
【解决方案3】:

IMO,处理这种情况的最佳方法是创建自定义控件:

     class MyScrollViewer : ScrollViewer
     {
         protected override void OnPreviewMouseWheel(MouseWheelEventArgs e)
         {
            base.OnPreviewMouseWheel(e);
            if (!e.Handled)
            {
                e.Handled = true;
                this.RaiseEvent(new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
                {
                    RoutedEvent = UIElement.MouseWheelEvent,
                    Source = this
                });
            }
        }
    }

【讨论】:

  • 你的答案是最好的,因为其他答案会删除标题,要解决这个问题,你需要从地面实现 ScrollViewer 参见ref1help
【解决方案4】:

somehelpfulanswers 的启发,我有一个实现,当内部(包括来自 ListView、ListBox、DataGrid)滚动超过其顶部/底部时滚动祖先 ScrollViewers。

我将附加属性应用于 App.xaml 中的所有 ScrollViewer:

<Style TargetType="ScrollViewer" BasedOn="{StaticResource {x:Type ScrollViewer}}">
    <Setter Property="local:ScrollViewerHelper.FixMouseWheel" Value="True" />
</Style>

附加属性检测滚动超过顶部/底部,当发生这种情况时,会在 ScrollViewer 的父级上引发鼠标滚轮事件。事件路由获取到外层 ScrollViewer:

public static class ScrollViewerHelper
{
    // Attached property boilerplate
    public static bool GetFixMouseWheel(ScrollViewer scrollViewer) => (bool)scrollViewer?.GetValue(FixMouseWheelProperty);
    public static void SetFixMouseWheel(ScrollViewer scrollViewer, bool value) => scrollViewer?.SetValue(FixMouseWheelProperty, value);
    public static readonly DependencyProperty FixMouseWheelProperty =
        DependencyProperty.RegisterAttached("FixMouseWheel", typeof(bool), typeof(ScrollViewerHelper),
            new PropertyMetadata(OnFixMouseWheelChanged));
    // End attached property boilerplate

    static void OnFixMouseWheelChanged(DependencyObject d,
                                       DependencyPropertyChangedEventArgs e)
    {
        var scrollViewer = d as ScrollViewer;
        if (scrollViewer == null) return;

        scrollViewer.PreviewMouseWheel += (s2, e2) =>
        {
            var parent = scrollViewer.Parent as UIElement;
            bool hitTopOrBottom = HitTopOrBottom(e2.Delta, scrollViewer);
            if (parent is null || !hitTopOrBottom) return;

            var argsCopy = Copy(e2);
            parent.RaiseEvent(argsCopy);
        };
    }

    static bool HitTopOrBottom(double delta, ScrollViewer scrollViewer)
    {
        var contentVerticalOffset = scrollViewer.ContentVerticalOffset;

        var atTop = contentVerticalOffset == 0;
        var movedUp = delta > 0;
        var hitTop = atTop && movedUp;

        var atBottom =
            contentVerticalOffset == scrollViewer.ScrollableHeight;
        var movedDown = delta < 0;
        var hitBottom = atBottom && movedDown;

        return hitTop || hitBottom;
    }

    static MouseWheelEventArgs Copy(MouseWheelEventArgs e)
        => new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
        {
            RoutedEvent = UIElement.MouseWheelEvent,
            Source = e.Source,
        };
}

【讨论】:

    【解决方案5】:

    如果您将内部列表视图包装在滚动查看器中,则滚动将起作用。

    <ListView ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
                    <ListView>
                        <ListView.ItemTemplate>
                            <DataTemplate>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                </ScrollViewer>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    

    【讨论】:

      猜你喜欢
      • 2012-06-14
      • 1970-01-01
      • 1970-01-01
      • 2010-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多