private int VerifyRealizedRange(ItemsRepeater repeater, CustomItemsSource dataSource) { int numRealized = 0; // trace Log.Comment("index:ItemsSourceView:Item"); for (int i = 0; i < dataSource.Inner.Count; i++) { var element = repeater.TryGetElement(i); if (element != null) { var data = ((TextBlock)element).Text; Log.Comment("{0} {1}:[{2}]", i, dataSource.GetAt(i), data); numRealized++; } else { Log.Comment(i + ":[null]"); } } // verify for (int i = 0; i < dataSource.Inner.Count; i++) { var element = repeater.TryGetElement(i); if (element != null) { var data = ((TextBlock)element).Text; Verify.AreEqual(dataSource.GetAt(i).ToString(), data); } } return(numRealized); }
public void ValidateMappingAndAutoRecycling() { ItemsRepeater repeater = null; ScrollViewer scrollViewer = null; RunOnUIThread.Execute(() => { var layout = new MockVirtualizingLayout() { MeasureLayoutFunc = (availableSize, context) => { var element0 = context.GetOrCreateElementAt(index: 0); // lookup - repeater will give back the same element and note that this element will not // be pinned - i.e it will be auto recycled after a measure pass where GetElementAt(0) is not called. var element0lookup = context.GetOrCreateElementAt(index: 0, options: ElementRealizationOptions.None); var element1 = context.GetOrCreateElementAt(index: 1, options: ElementRealizationOptions.ForceCreate | ElementRealizationOptions.SuppressAutoRecycle); // forcing a new element for index 1 that will be pinned (not auto recycled). This will be // a completely new element. Repeater does not do the mapping/lookup when forceCreate is true. var element1Clone = context.GetOrCreateElementAt(index: 1, options: ElementRealizationOptions.ForceCreate | ElementRealizationOptions.SuppressAutoRecycle); Verify.AreSame(element0, element0lookup); Verify.AreNotSame(element1, element1Clone); element0.Measure(availableSize); element1.Measure(availableSize); element1Clone.Measure(availableSize); return(new Size(100, 100)); }, }; Content = CreateAndInitializeRepeater( itemsSource: Enumerable.Range(0, 5), layout: layout, elementFactory: GetDataTemplate("<Button>Hello</Button>"), repeater: ref repeater, scrollViewer: ref scrollViewer); Content.UpdateLayout(); Verify.IsNotNull(repeater.TryGetElement(0)); Verify.IsNotNull(repeater.TryGetElement(1)); layout.MeasureLayoutFunc = null; repeater.InvalidateMeasure(); Content.UpdateLayout(); Verify.IsNull(repeater.TryGetElement(0)); // not pinned, should be auto recycled. Verify.IsNotNull(repeater.TryGetElement(1)); // pinned, should stay alive }); }
public void ValidateDataContextGetsPropagated() { const string c_element1DataContext = "Element1_DataContext"; RunOnUIThread.Execute(() => { var data = new List <Button>() { new Button() { Content = "Element1_Content", DataContext = c_element1DataContext } }; var elementFactory = new ElementFromElementElementFactory(); var repeater = new ItemsRepeater() { ItemsSource = data, ItemTemplate = elementFactory }; Content = repeater; Content.UpdateLayout(); // Verify that DataContext of data has propagated to the container var firstElement = repeater.TryGetElement(0) as Button; var retrievedDataContextItem1 = firstElement.DataContext as string; Verify.IsTrue(data[0] == firstElement.Content); Verify.IsTrue(retrievedDataContextItem1 == c_element1DataContext); }); }
public void ValidateDataContextDoesNotGetOverwritten() { const string c_element1DataContext = "Element1_DataContext"; RunOnUIThread.Execute(() => { var data = new List <Button>() { new Button() { Content = "Element1_Content", DataContext = c_element1DataContext } }; var elementFactory = new DataAsElementElementFactory(); var repeater = new ItemsRepeater() { ItemsSource = data, ItemTemplate = elementFactory }; Content = repeater; Content.UpdateLayout(); // Verify that DataContext is still the same var firstElement = repeater.TryGetElement(0) as Button; var retrievedDataContextItem1 = firstElement.DataContext as string; Verify.IsTrue(retrievedDataContextItem1 == c_element1DataContext); }); }
public void ValidateStackLayoutDisabledVirtualizationWithItemsRepeater() { RunOnUIThread.Execute(() => { var repeater = new ItemsRepeater(); var stackLayout = new StackLayout(); stackLayout.DisableVirtualization = true; repeater.Layout = stackLayout; repeater.ItemsSource = Enumerable.Range(0, 10); repeater.ItemTemplate = (DataTemplate)XamlReader.Parse( @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'> <Button Content='{Binding}' Height='100' /> </DataTemplate>"); var scrollViewer = new ScrollViewer() { Content = repeater }; scrollViewer.Height = 100; Content = scrollViewer; Content.UpdateLayout(); for (int i = 0; i < repeater.ItemsSourceView.Count; i++) { var child = repeater.TryGetElement(i) as Button; Verify.IsNotNull(child); } }); }
public void ValidateNonVirtualLayoutWithItemsRepeater() { RunOnUIThread.Execute(() => { var repeater = new ItemsRepeater(); repeater.Layout = new NonVirtualStackLayout(); repeater.ItemsSource = Enumerable.Range(0, 10); repeater.ItemTemplate = (DataTemplate)XamlReader.Parse( @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'> <Button Content='{Binding}' Height='100' /> </DataTemplate>"); Content = repeater; Content.UpdateLayout(); double expectedYOffset = 0; for (int i = 0; i < repeater.ItemsSourceView.Count; i++) { var child = repeater.TryGetElement(i) as Button; Verify.IsNotNull(child); var layoutBounds = LayoutInformation.GetLayoutSlot(child); Verify.AreEqual(expectedYOffset, layoutBounds.Y); Verify.AreEqual(i, child.Content); expectedYOffset += 100; } }); }
public void CanResetLayoutAfterUniqueIdReset() { var data = new WinRTCollection(Enumerable.Range(0, 2).Select(i => string.Format("Item #{0}", i))); object dataSource = null; RunOnUIThread.Execute(() => dataSource = MockItemsSource.CreateDataSource(data, supportsUniqueIds: true)); ItemsRepeater repeater = SetupRepeater(dataSource); RunOnUIThread.Execute(() => { var range = new UIElement[] { repeater.TryGetElement(0), repeater.TryGetElement(1) }; var clearedElements = new List <UIElement>(); repeater.ElementClearing += (s, e) => { clearedElements.Add(e.Element); }; // The realized elements will be sent to the unique id reset pool. // They haven't been cleared yet. data.Reset(); Verify.AreEqual(0, clearedElements.Count); // This also cause elements to be sent to the unique id reset pool. // We are validating here that we are smart enough not send them there twice. // Doing so will cause an exception to be thrown. repeater.Layout = null; Verify.AreEqual(0, clearedElements.Count); repeater.UpdateLayout(); // Layout runs. The elements in the reset pool are not used. // They should be cleared back to the view generator at this point. Verify.AreEqual(2, clearedElements.Count); Verify.AreEqual(range[0], clearedElements[0]); Verify.AreEqual(range[1], clearedElements[1]); Verify.IsNull(repeater.TryGetElement(0)); Verify.IsNull(repeater.TryGetElement(1)); }); }
public void CanChangeFocusAfterUniqueIdReset() { var data = new WinRTCollection(Enumerable.Range(0, 2).Select(i => string.Format("Item #{0}", i))); object dataSource = null; RunOnUIThread.Execute(() => dataSource = MockItemsSource.CreateDataSource(data, supportsUniqueIds: true)); ItemsRepeater repeater = SetupRepeater(dataSource); Control focusedElement = null; RunOnUIThread.Execute(() => { focusedElement = (Control)repeater.TryGetElement(0); focusedElement.Focus(); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { data.Reset(); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { // Still focused. Verify.AreEqual(focusedElement, Keyboard.FocusedElement); // Change focused element. focusedElement = (Control)repeater.TryGetElement(1); focusedElement.Focus(); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { // Focus is on the new element. Verify.AreEqual(focusedElement, Keyboard.FocusedElement); }); }
private VirtualizingLayout CreateLayout(ItemsRepeater repeater) { var layout = new MockVirtualizingLayout(); var children = new List <UIElement>(); layout.MeasureLayoutFunc = (availableSize, context) => { repeater.Tag = repeater.Tag ?? context; children.Clear(); var itemCount = context.ItemCount; for (int i = 0; i < itemCount; ++i) { var element = repeater.TryGetElement(i) ?? context.GetOrCreateElementAt(i); element.Measure(availableSize); children.Add(element); } return(new Size(10, 10)); }; return(layout); }
private void MoveFocusToIndex(ItemsRepeater repeater, int index) { var element = repeater.TryGetElement(index) as Control; element.Focus(); }
// [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(); }); 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], Keyboard.FocusedElement); }); }
private void ValidateRealizedRange( ItemsRepeater repeater, int expectedFirstGroupIndex, int expectedLastGroupIndex, int expectedFirstItemGroupIndex, int expectedFirstItemIndex, int expectedLastItemGroupIndex, int expectedLastItemIndex) { int actualFirstGroupIndex = -1; int actualLastGroupIndex = -1; int actualFirstItemGroupIndex = -1; int actualFirstItemIndex = -1; int actualLastItemGroupIndex = -1; int actualLastItemIndex = -1; RunOnUIThread.Execute(() => { int groupIndex = 0; int itemIndex = 0; var groups = (IEnumerable <NamedGroup <string> >)repeater.ItemsSource; foreach (var group in groups) { var groupElement = repeater.TryGetElement(groupIndex); if (groupElement != null) { actualFirstGroupIndex = actualFirstGroupIndex == -1 ? groupIndex : actualFirstGroupIndex; actualLastGroupIndex = groupIndex; var innerRepeater = (ItemsRepeater)((FrameworkElement)groupElement).FindName("InnerRepeater"); foreach (var item in group) { var itemElement = innerRepeater.TryGetElement(itemIndex); if (itemElement != null) { actualFirstItemGroupIndex = actualFirstItemGroupIndex == -1 ? groupIndex : actualFirstItemGroupIndex; actualFirstItemIndex = actualFirstItemIndex == -1 ? itemIndex : actualFirstItemIndex; actualLastItemGroupIndex = groupIndex; actualLastItemIndex = itemIndex; } ++itemIndex; } } itemIndex = 0; ++groupIndex; } }); Verify.AreEqual(expectedFirstGroupIndex, actualFirstGroupIndex); Verify.AreEqual(expectedLastGroupIndex, actualLastGroupIndex); Verify.AreEqual(expectedFirstItemGroupIndex, actualFirstItemGroupIndex); Verify.AreEqual(expectedFirstItemIndex, actualFirstItemIndex); Verify.AreEqual(expectedLastItemGroupIndex, actualLastItemGroupIndex); Verify.AreEqual(expectedLastItemIndex, actualLastItemIndex); }