private void ValidateCurrentFocus(ItemsRepeater repeater, int expectedIndex, string expectedContent) { var currentFocus = Keyboard.FocusedElement 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()); }
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("pack://application:,,,/Images/recipe0.png"), Description = "added recipe", }); } }
// [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(); }); 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(); }); 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(); }); 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); }); }