zoukankan      html  css  js  c++  java
  • 解决WPF ListView(ListBox) 嵌套元素无法滚动的问题

    我需要实现一个类似QQ好友分组的数据展示,需要用到两个 ListView 嵌套,代码大致如下:

    <ListView
              ItemsSource="{Binding datas}"
        <ListView.ItemTemplate>
            <DataTemplate>
                <Expander>
                    <Expander.Header>
                        <TextBlock Text="{Binding name}"/>
                    </Expander.Header>
                    <Expander.Content>
                        <ListView
                                  ItemsSource="{Binding name}"
                                  >
                        </ListView>
                    </Expander.Content>
                </Expander>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    

    但当把数据绑定上去后,发现分组元素可以滚动,但分组内的元素无法滚动:
    problem1

    根据网上大家所说是因为 ListView 内本身就含有一个 ScrollViewer,当两个 ListView 嵌套时,鼠标滚轮事件首先被内层的 ListView 接收,而内层的 ListView 的滚动条在此时是被禁用的(至少看起来是这样的),此时当数据超出一定长度时显示出来的滚动条是外部 ListView 的,故当鼠标在内层 ListView 中滚动时,内层的元素无法滚动。

    自此解决思路自然是将内部滚轮事件拦截下来,标记为已处理,然后手动激发一个滚轮事件,并将这个事件冒泡至上层的 ListView 来进行处理,于是添加一个 PreviewMouseWheel 事件:

    <ListView
              ItemsSource="{Binding datas}"
        <ListView.ItemTemplate>
            <DataTemplate>
                <Expander>
                    <Expander.Header>
                        <TextBlock Text="{Binding name}"/>
                    </Expander.Header>
                    <Expander.Content>
                        <ListView
                                  PreviewMouseWheel="ListView_PreviewMouseWheel"
                                  ItemsSource="{Binding name}"
                                  >
                        </ListView>
                    </Expander.Content>
                </Expander>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    
    private void ListView_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        if (!e.Handled)
        {
            // ListView拦截鼠标滚轮事件
            e.Handled = true;
    
            // 激发一个鼠标滚轮事件,冒泡给外层ListView接收到
            var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
            eventArg.RoutedEvent = UIElement.MouseWheelEvent;
            eventArg.Source = sender;
            var parent = ((Control)sender).Parent as UIElement;
            parent.RaiseEvent(eventArg);
        }
    }
    

    此时虽然鼠标滚轮事件在内层也能工作了,但是却出现了新的问题:
    problem2

    此时滚轮滚动过的单位依然是外层元素的实际高度(外层元素所包含的所有内层 ListView 的高度)。

    这里我想到的方法是在外层 ListView 上嵌套一个 ScrollViewer ,并将外层 ListView 的鼠标滚轮事件冒泡给 ScrollViewer 来处理,这样外层 ScrollViewer 便能接收到最内层 ListView 的鼠标滚轮事件了:
    over
    大致代码如下:

    <ScrollViewer>
        <ListView
                  ItemsSource="{Binding datas}"
                  PreviewMouseWheel="ListView_PreviewMouseWheel"
                  >
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Expander>
                        <Expander.Header>
                            <TextBlock Text="{Binding name}"/>
                        </Expander.Header>
                        <Expander.Content>
                            <ListView
                                      PreviewMouseWheel="ListView_PreviewMouseWheel"
                                      ItemsSource="{Binding name}"
                                      >
                            </ListView>
                        </Expander.Content>
                    </Expander>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </ScrollViewer>
    
    private void ListView_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        if (!e.Handled)
        {
            // ListView拦截鼠标滚轮事件
            e.Handled = true;
    
            // 激发一个鼠标滚轮事件,冒泡给外层ListView接收到
            var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
            eventArg.RoutedEvent = UIElement.MouseWheelEvent;
            eventArg.Source = sender;
            var parent = ((Control)sender).Parent as UIElement;
            parent.RaiseEvent(eventArg);
        }
    }
    

    完整代码:Github

  • 相关阅读:
    Cocos游戏引擎,让小保安成就大梦想
    Android 高仿QQ5.2双向側滑菜单DrawerLayout实现源代码
    Java中字符串相等与大小比較
    Android四大基本组件之 Activity
    C++基础学习教程(五)
    HAWQ技术解析(八) —— 大表分区
    Jenkins 安装与使用--实例
    Android多点触控技术,实现对图片的放大缩小平移,惯性滑动等功能
    Mycat(4):消息表mysql数据库分表实践
    谋哥:《App自推广》开篇之回到远古人类
  • 原文地址:https://www.cnblogs.com/Jaywhen-xiang/p/14253621.html
Copyright © 2011-2022 走看看