private static Button[] GetRealizedRange(ItemsRepeater repeater) { return(Enumerable.Range(0, VisualTreeHelper.GetChildrenCount(repeater)) .Select(i => (Button)VisualTreeHelper.GetChild(repeater, i)) .Where(e => repeater.GetElementIndex(e) >= 0) .OrderBy(e => repeater.GetElementIndex(e)) .ToArray()); }
public void ValidateRepeaterDefaults() { RunOnUIThread.Execute(() => { var repeater = new ItemsRepeater() { ItemsSource = Enumerable.Range(0, 10).Select(i => string.Format("Item #{0}", i)), }; Content = new ItemsRepeaterScrollHost() { Width = 400, Height = 800, ScrollViewer = new ScrollViewer { Content = repeater } }; Content.UpdateLayout(); for (int i = 0; i < 10; i++) { var element = repeater.TryGetElement(i); Verify.IsNotNull(element); Verify.AreEqual(string.Format("Item #{0}", i), ((TextBlock)element).Text); Verify.AreEqual(i, repeater.GetElementIndex(element)); } Verify.IsNull(repeater.TryGetElement(20)); }); }
private void ValidateCurrentFocus(ItemsRepeater repeater, int expectedIndex, string expectedContent) { var currentFocus = FocusManager.GetFocusedElement() as ContentControl; var currentFocusedIndex = repeater.GetElementIndex(currentFocus); Log.Comment("expectedIndex: " + expectedIndex + " actual : " + currentFocusedIndex); Verify.AreEqual(expectedIndex, currentFocusedIndex); Log.Comment("expectedContent: " + expectedContent + " actual : " + currentFocus.Content.ToString()); Verify.AreEqual(expectedContent, currentFocus.Content.ToString()); }
public void ValidateElementToIndexMapping() { ItemsRepeater repeater = null; RunOnUIThread.Execute(() => { var elementFactory = new RecyclingElementFactory(); elementFactory.RecyclePool = new RecyclePool(); elementFactory.Templates["Item"] = (DataTemplate)XamlReader.Load( @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'> <TextBlock Text='{Binding}' Height='50' /> </DataTemplate>"); repeater = new ItemsRepeater() { ItemsSource = Enumerable.Range(0, 10).Select(i => string.Format("Item #{0}", i)), #if BUILD_WINDOWS ItemTemplate = (Windows.UI.Xaml.IElementFactory)elementFactory, #else ItemTemplate = elementFactory, #endif // Default is StackLayout, so do not have to explicitly set. // Layout = new StackLayout(), }; Content = new ItemsRepeaterScrollHost() { Width = 400, Height = 800, ScrollViewer = new ScrollViewer { Content = repeater } }; Content.UpdateLayout(); for (int i = 0; i < 10; i++) { var element = repeater.TryGetElement(i); Verify.IsNotNull(element); Verify.AreEqual(string.Format("Item #{0}", i), ((TextBlock)element).Text); Verify.AreEqual(i, repeater.GetElementIndex(element)); } Verify.IsNull(repeater.TryGetElement(20)); }); }
private void OnRecipeDeleted(object sender, RoutedEventArgs e) { if (_flatData != null) { // walk up the tree to find the container and repeater. var container = (FrameworkElement)sender; while (!(container.Parent is ItemsRepeater)) { container = (FrameworkElement)container.Parent; } ItemsRepeater repeater = (ItemsRepeater)container.Parent; int index = repeater.GetElementIndex(container); _flatData.RemoveAt(index); } }
private void OnRecipeInserted(object sender, RoutedEventArgs e) { if (_flatData != null) { // walk up the tree to find the container and repeater. var container = (FrameworkElement)sender; while (!(container.Parent is ItemsRepeater)) { container = (FrameworkElement)container.Parent; } ItemsRepeater repeater = (ItemsRepeater)container.Parent; int index = repeater.GetElementIndex(container) + 1; _flatData.Insert(index, new Recipe() { ImageUri = new Uri("ms-appx:///Images/recipe0.png"), Description = "added recipe", }); } }
public void VerifyCurrentAnchor() { ItemsRepeater rootRepeater = null; ScrollViewer scrollViewer = null; ItemsRepeaterScrollHost scrollhost = null; ManualResetEvent viewChanged = new ManualResetEvent(false); RunOnUIThread.Execute(() => { scrollhost = (ItemsRepeaterScrollHost)XamlReader.Load( @"<controls:ItemsRepeaterScrollHost Width='400' Height='600' xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' xmlns:controls='using:Microsoft.UI.Xaml.Controls'> <controls:ItemsRepeaterScrollHost.Resources> <DataTemplate x:Key='ItemTemplate' > <TextBlock Text='{Binding}' Height='50'/> </DataTemplate> </controls:ItemsRepeaterScrollHost.Resources> <ScrollViewer x:Name='scrollviewer'> <controls:ItemsRepeater x:Name='rootRepeater' ItemTemplate='{StaticResource ItemTemplate}' VerticalCacheLength='0' /> </ScrollViewer> </controls:ItemsRepeaterScrollHost>"); rootRepeater = (ItemsRepeater)scrollhost.FindName("rootRepeater"); scrollViewer = (ScrollViewer)scrollhost.FindName("scrollviewer"); scrollViewer.ViewChanged += (sender, args) => { if (!args.IsIntermediate) { viewChanged.Set(); } }; rootRepeater.ItemsSource = Enumerable.Range(0, 500); Content = scrollhost; }); // scroll down several times and validate current anchor for (int i = 1; i < 10; i++) { IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { scrollViewer.ChangeView(null, i * 200, null); }); Verify.IsTrue(viewChanged.WaitOne(DefaultWaitTimeInMS)); viewChanged.Reset(); RunOnUIThread.Execute(() => { Verify.AreEqual(i * 200, scrollViewer.VerticalOffset); var anchor = PlatformConfiguration.IsOSVersionLessThan(OSVersion.Redstone5) ? scrollhost.CurrentAnchor : scrollViewer.CurrentAnchor; var anchorIndex = rootRepeater.GetElementIndex(anchor); Log.Comment("CurrentAnchor: " + anchorIndex); Verify.AreEqual(i * 4, anchorIndex); }); } }
// [TestMethod] Issue #1018 public void CanPinFocusedElements() { // Setup a grouped repeater scenario with two groups each containing two items. var data = new ObservableCollection <ObservableCollection <string> >(Enumerable .Range(0, 2) .Select(i => new ObservableCollection <string>(Enumerable .Range(0, 2) .Select(j => string.Format("Item #{0}.{1}", i, j))))); List <ContentControl>[] itemElements = null; ItemsRepeater[] innerRepeaters = null; List <StackPanel> groupElements = null; ItemsRepeater rootRepeater = null; var gotFocus = new ManualResetEvent(false); RunOnUIThread.Execute(() => { itemElements = new[] { Enumerable.Range(0, 2).Select(i => new ContentControl()).ToList(), Enumerable.Range(0, 2).Select(i => new ContentControl()).ToList() }; itemElements[0][0].GotFocus += delegate { gotFocus.Set(); }; innerRepeaters = Enumerable.Range(0, 2).Select(i => CreateRepeater( MockItemsSource.CreateDataSource(data[i], supportsUniqueIds: false), MockElementFactory.CreateElementFactory(itemElements[i]))).ToArray(); groupElements = Enumerable.Range(0, 2).Select(i => { var panel = new StackPanel(); panel.Children.Add(new ContentControl()); panel.Children.Add(innerRepeaters[i]); return(panel); }).ToList(); rootRepeater = CreateRepeater( MockItemsSource.CreateDataSource(data, supportsUniqueIds: false), MockElementFactory.CreateElementFactory(groupElements)); Content = rootRepeater; rootRepeater.UpdateLayout(); itemElements[0][0].Focus(FocusState.Keyboard); }); Verify.IsTrue(gotFocus.WaitOne(DefaultWaitTimeInMS), "Waiting for focus event on the first element of the first group."); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Log.Comment("Recycle focused element 0.0 and validate it's still realized because it is pinned."); { var ctx = (VirtualizingLayoutContext)innerRepeaters[0].Tag; ctx.RecycleElement(itemElements[0][0]); Verify.AreEqual(0, innerRepeaters[0].GetElementIndex(itemElements[0][0])); } Log.Comment("Recycle element 0.1 and validate it's no longer realized because it is not pinned."); { var ctx = (VirtualizingLayoutContext)innerRepeaters[0].Tag; ctx.RecycleElement(itemElements[0][1]); Verify.AreEqual(-1, innerRepeaters[0].GetElementIndex(itemElements[0][1])); } Log.Comment("Recycle group 0 and validate it's still realized because one of its items is pinned."); { var ctx = (VirtualizingLayoutContext)rootRepeater.Tag; ctx.RecycleElement(groupElements[0]); Verify.AreEqual(0, rootRepeater.GetElementIndex(groupElements[0])); } itemElements[1][1].GotFocus += delegate { gotFocus.Set(); }; itemElements[1][1].Focus(FocusState.Keyboard); }); Verify.IsTrue(gotFocus.WaitOne(DefaultWaitTimeInMS), "Waiting for focus event on the second element of the second group."); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Log.Comment(@"Move focus to item 1.1 and validate item 0.0 and group 0 are recycled because the only thing keeping them around is the fact that item 0.0 was focus pinned"); { ((VirtualizingLayoutContext)rootRepeater.Tag).RecycleElement(groupElements[0]); ((VirtualizingLayoutContext)innerRepeaters[0].Tag).RecycleElement(itemElements[0][0]); Verify.AreEqual(-1, rootRepeater.GetElementIndex(groupElements[0])); Verify.AreEqual(-1, innerRepeaters[0].GetElementIndex(itemElements[0][0])); Verify.AreEqual(1, innerRepeaters[0].GetElementIndex(itemElements[1][1])); } Log.Comment(@"Delete item 1.1 from the data. This will force the element to get recycled even if it's pinned."); { data[1].RemoveAt(1); rootRepeater.UpdateLayout(); Verify.AreEqual(-1, innerRepeaters[1].GetElementIndex(itemElements[1][1])); } }); }
// [TestMethod] Issue 1018 public void CanReuseElementsDuringUniqueIdReset() { var data = new WinRTCollection(Enumerable.Range(0, 2).Select(i => string.Format("Item #{0}", i))); List <UIElement> mapping = null; ItemsRepeater repeater = null; MockElementFactory elementFactory = null; ContentControl focusedElement = null; RunOnUIThread.Execute(() => { mapping = new List <UIElement> { new ContentControl(), new ContentControl() }; repeater = CreateRepeater( MockItemsSource.CreateDataSource(data, supportsUniqueIds: true), MockElementFactory.CreateElementFactory(mapping)); elementFactory = (MockElementFactory)repeater.ItemTemplate; Content = repeater; repeater.UpdateLayout(); focusedElement = (ContentControl)repeater.TryGetElement(1); focusedElement.Focus(FocusState.Keyboard); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { elementFactory.ValidateGetElementCalls( new MockElementFactory.GetElementCallInfo(0, repeater), new MockElementFactory.GetElementCallInfo(1, repeater)); elementFactory.ValidateRecycleElementCalls(); data.ResetWith(new[] { data[0], "New item" }); Verify.AreEqual(0, repeater.GetElementIndex(mapping[0])); Verify.AreEqual(1, repeater.GetElementIndex(mapping[1])); Verify.IsNull(repeater.TryGetElement(0)); Verify.IsNull(repeater.TryGetElement(1)); elementFactory.ValidateGetElementCalls(/* GetElement should not be called */); elementFactory.ValidateRecycleElementCalls(/* RecycleElement should not be called */); mapping[1] = new ContentControl(); // For "New Item" repeater.UpdateLayout(); Verify.AreEqual(0, repeater.GetElementIndex(mapping[0])); Verify.AreEqual(1, repeater.GetElementIndex(mapping[1])); Verify.AreEqual(mapping[0], repeater.TryGetElement(0)); Verify.AreEqual(mapping[1], repeater.TryGetElement(1)); elementFactory.ValidateGetElementCalls( new MockElementFactory.GetElementCallInfo(1, repeater)); elementFactory.ValidateRecycleElementCalls( new MockElementFactory.RecycleElementCallInfo(focusedElement, repeater)); // If the focused element survived the reset, we will keep focus on it. If not, we // try to find one based on the index. In this case, the focused element (index 1) // got recycled, and we still have index 1 after the stable reset, so the new index 1 // will get focused. Note that recycling the elements to view generator in the case of // stable reset happens during the arrange, so by that time we will have pulled elements // from the stable reset pool and maybe created some new elements as well. int index = repeater.GetElementIndex(focusedElement); Log.Comment("focused index " + index); Verify.AreEqual(mapping[1], FocusManager.GetFocusedElement()); }); }