在ListView中获取第一个可见组无法正常工作 [英] Getting the first visible group in ListView does not work properly

查看:70
本文介绍了在ListView中获取第一个可见组无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个示例应用程序,其中有一个分组的ListView,并且在滚动列表视图时,我想要在UI中获得顶部可见的组(第一个可见组).但是,当我继续在基于触摸的设备上滚动时,只要我将手指放在该设备上,它就会开始显示下一个组(在顶部可见组旁边).如果我松开手指,它将纠正该值. 这是我的示例应用程序: https: //onedrive.live.com/redir?resid=91B2B9D9EA21A110!615&authkey=!AKJV0b_q7g-YZF4&ithint=file%2czip

I have created a sample app where I have a grouped ListView and while scrolling through the listview I want to get the top visible group in the UI (first visible group). But when I keep scrolling on a touch based device, it starts showing the next group (next to the top visible group) for as long as I keep my finger on the device. If I remove my fingers, it would correct the value. Here is my sample app: https://onedrive.live.com/redir?resid=91B2B9D9EA21A110!615&authkey=!AKJV0b_q7g-YZF4&ithint=file%2czip

示例代码:

public sealed partial class MainPage : Page
    {
        public ViewModel MyVM = new ViewModel();
        public MainPage()
        {
            this.InitializeComponent();

            lv.SizeChanged += (s, e) =>
            {
                ScrollViewer sv = FindVisualChildren<ScrollViewer>(lv).FirstOrDefault();
                if (sv != null)
                {
                    sv.ViewChanged += (ss, ee) =>
                    {
                        IEnumerable<TextBlock> tblocks = FindVisualChildren<TextBlock>(lv).Where(x => x.Name == "tbHeader");
                        if (tblocks != null)
                        {
                            foreach (TextBlock tblock in tblocks)
                            {
                                if (IsVisibileToUser(tblock, sv))
                                {
                                    first.Text = tblock.Text;
                                    break;
                                }
                            }
                        }
                    };
                }
            };
        }

        private static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
        {
            if (depObj != null)
            {
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
                {
                    DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                    if (child != null && child is T)
                    {
                        yield return (T)child;
                    }

                    foreach (T childOfChild in FindVisualChildren<T>(child))
                    {
                        yield return childOfChild;
                    }
                }
            }
        }

        private bool IsVisibileToUser(FrameworkElement element, FrameworkElement container)
        {
            if (element == null || container == null)
                return false;

            if (element.Visibility != Visibility.Visible)
                return false;

            Rect elementBounds = element.TransformToVisual(container).TransformBounds(new Rect(0.0, 0.0, element.ActualWidth, element.ActualHeight));
            Rect containerBounds = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight);

            return (elementBounds.Top < containerBounds.Bottom && elementBounds.Bottom > containerBounds.Top);
        }
    }

public class ClassA
    {
        public DateTime DateTimePropertyOfClassA { get; set; }
    }

public class ViewModel
    {
        public ViewModel()
        {
            //return a grouped collection:
            Grouped = from x in CollectionOfClassA group x by x.DateTimePropertyOfClassA into grp orderby grp.Key select grp;
        }

        public IList<ClassA> CollectionOfClassA { get; set; } = new List<ClassA>()
        {
            new ClassA(){ DateTimePropertyOfClassA = DateTime.Parse("2016-01-01")},
            new ClassA(){ DateTimePropertyOfClassA = DateTime.Parse("2016-03-01")},
            new ClassA(){ DateTimePropertyOfClassA = DateTime.Parse("2016-04-01")},
            new ClassA(){ DateTimePropertyOfClassA = DateTime.Parse("2016-05-01")},
            new ClassA(){ DateTimePropertyOfClassA = DateTime.Parse("2016-06-01")},
            new ClassA(){ DateTimePropertyOfClassA =DateTime.Parse("2016-07-01")},
            new ClassA(){ DateTimePropertyOfClassA = DateTime.Parse("2016-08-01")},
            new ClassA(){ DateTimePropertyOfClassA = DateTime.Parse("2016-09-01")},
            new ClassA(){ DateTimePropertyOfClassA = DateTime.Parse("2016-11-01")},
            new ClassA(){ DateTimePropertyOfClassA = DateTime.Parse("2016-12-01")},
            new ClassA(){ DateTimePropertyOfClassA = DateTime.Parse("2016-03-01")},
            new ClassA(){ DateTimePropertyOfClassA =DateTime.Parse("2016-06-01")},
            new ClassA(){ DateTimePropertyOfClassA = DateTime.Parse("2016-01-01")},
            new ClassA(){ DateTimePropertyOfClassA = DateTime.Parse("2016-03-01")},
            new ClassA(){ DateTimePropertyOfClassA = DateTime.Parse("2016-03-01")},
            new ClassA(){ DateTimePropertyOfClassA = DateTime.Parse("2016-03-01")},
            new ClassA(){ DateTimePropertyOfClassA = DateTime.Parse("2016-03-01")},
            new ClassA(){ DateTimePropertyOfClassA =DateTime.Parse("2016-06-01")}
        };

        public IEnumerable<object> Grouped { get; }
    }

Xaml:

<Page.Resources>
    <CollectionViewSource x:Name="cvs"
                      IsSourceGrouped="True"
                      Source="{x:Bind MyVM.Grouped, Mode=OneWay}"/>
</Page.Resources>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <TextBlock Name="first" HorizontalAlignment="Center" Visibility="Visible" FontSize="12"></TextBlock>
    <ListView Grid.Row="1" Name="lv" ItemsSource="{Binding Source={StaticResource cvs}}" ScrollViewer.VerticalScrollBarVisibility="Visible">
        <ListView.GroupStyle>
            <GroupStyle>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock x:Name="tbHeader" FontSize="15" FontWeight="Bold" Text="{Binding Key}"/>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
            </GroupStyle>
        </ListView.GroupStyle>
    </ListView>
</Grid>

我可以做些什么来改善此功能吗?

Is there anything I can do to improve this functionality?

推荐答案

ScrollViewer.ViewChanged event will be fired several times during scrolling, we can't control how many times the IsVisibileToUser method be called in your code.

Rect elementBounds将在滚动过程中动态更改,这是您可以尝试的一种解决方法:将ScrollViewer中的区域减小为一个TextBlock的大小,例如:

Rect elementBounds will be dynamically changed during scrolling, here is a workaround you can try: reducing the region in the ScrollViewer to only one TextBlock's size, for example:

private bool IsVisibileToUser(FrameworkElement element, FrameworkElement container)
{
    if (element == null || container == null)
        return false;

    if (element.Visibility != Visibility.Visible)
        return false;

    Rect elementBounds = element.TransformToVisual(container).TransformBounds(new Rect(0.0, 0.0, element.ActualWidth, element.ActualHeight));
    Rect containerBounds = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight);

    return (elementBounds.Top <= element.ActualHeight && elementBounds.Bottom > containerBounds.Top);
}

这篇关于在ListView中获取第一个可见组无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆