获取ListView中的第一个可见组无法正常工作

时间:2016-06-16 07:57:35

标签: listview uwp

我创建了一个示例应用程序,其中我有一个分组的ListView,在滚动列表视图时,我希望获得UI中的顶部可见组(第一个可见组)。但是当我继续滚动基于触摸的设备时,只要我将手指放在设备上,它就会开始显示下一组(顶部可见组旁边)。如果我移开我的手指,它会纠正该值。 以下是我的示例应用: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>

我有什么办法可以改善这项功能吗?

1 个答案:

答案 0 :(得分:2)

滚动期间会多次触发

ScrollViewer.ViewChanged event,我们无法控制代码中调用IsVisibileToUser方法的次数。

滚动期间会动态更改

Rect elementBounds,这是您可以尝试的解决方法:将ScrollViewer中的区域缩小为仅TextBlock的一个大小,例如:

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