studio programacion para móviles libro edición desarrollo desarrollar curso aprende aplicaciones listview uwp

programacion - Obtener el primer grupo visible en ListView no funciona correctamente



manual de programacion android pdf (1)

He creado una aplicación de muestra en la que tengo un ListView agrupado y, al desplazarme por la vista de lista, quiero obtener el grupo visible superior en la IU (primer grupo visible). Pero cuando sigo desplazándome en un dispositivo táctil, comienza a mostrar el siguiente grupo (al lado del grupo visible superior) mientras sigo con el dedo en el dispositivo. Si elimino mis dedos, corregirá el valor. Aquí está mi aplicación de ejemplo: https://onedrive.live.com/redir?resid=91B2B9D9EA21A110!615&authkey=!AKJV0b_q7g-YZF4&ithint=file%2czip

Código de muestra:

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>

¿Hay algo que pueda hacer para mejorar esta funcionalidad?


El evento ScrollViewer.ViewChanged se disparará varias veces durante el desplazamiento, no podemos controlar cuántas veces se IsVisibileToUser método IsVisibileToUser en su código.

Rect elementBounds cambiará dinámicamente durante el desplazamiento, aquí hay una solución que puede intentar: reducir la región en el ScrollViewer a solo un tamaño de TextBlock , por ejemplo:

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