private ItemsRepeater SetupRepeater(CustomItemsSource dataSource, ElementFactory elementFactory, ref ScrollViewer scrollViewer, VirtualizingLayout layout) { var repeater = new ItemsRepeater() { ItemsSource = dataSource, #if BUILD_WINDOWS ItemTemplate = (Windows.UI.Xaml.IElementFactory)elementFactory, #else ItemTemplate = elementFactory, #endif Layout = layout, VerticalCacheLength = 0, HorizontalCacheLength = 0 }; scrollViewer = new ScrollViewer { Content = repeater }; Content = new ItemsRepeaterScrollHost() { Width = 200, Height = 200, ScrollViewer = scrollViewer }; Content.UpdateLayout(); int realized = VerifyRealizedRange(repeater, dataSource); Verify.IsGreaterThan(realized, 0); return(repeater); }
private ItemsRepeater SetupRepeater(CustomItemsSource dataSource, ElementFactory elementFactory, ref ScrollViewer scrollViewer, VirtualizingLayout layout) { var repeater = new ItemsRepeater() { ItemsSource = dataSource, ItemTemplate = elementFactory, Layout = layout, VerticalCacheLength = 0, HorizontalCacheLength = 0 }; scrollViewer = new ScrollViewer { Content = repeater }; Content = new ItemsRepeaterScrollHost() { Width = 200, Height = 200, ScrollViewer = scrollViewer }; Content.UpdateLayout(); if (dataSource.Count > 0) { int realized = VerifyRealizedRange(repeater, dataSource); Verify.IsGreaterThan(realized, 0); } return(repeater); }
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)); }); }
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 ItemsRepeater SetupRepeater(object dataSource, VirtualizingLayout layout, string itemContent, out ScrollViewer scrollViewer) { ItemsRepeater repeater = null; ScrollViewer sv = 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'> " + itemContent + @"</DataTemplate>"); repeater = new ItemsRepeater() { ItemsSource = dataSource, #if BUILD_WINDOWS ItemTemplate = (Windows.UI.Xaml.IElementFactory)elementFactory, #else ItemTemplate = elementFactory, #endif Layout = layout, HorizontalCacheLength = 0.0, VerticalCacheLength = 0.0 }; sv = new ScrollViewer { Content = repeater }; Content = new ItemsRepeaterScrollHost() { Width = 200, Height = 200, ScrollViewer = sv }; }); IdleSynchronizer.Wait(); scrollViewer = sv; return(repeater); }
public void VerifyCorrectionsInNonScrollableDirection() { 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'> <ScrollViewer Width='400' Height='400' x:Name='scrollviewer'> <controls:ItemsRepeater x:Name='repeater'> <DataTemplate> <StackPanel> <controls:ItemsRepeater ItemsSource='{Binding}'> <controls:ItemsRepeater.Layout> <controls:StackLayout Orientation='Horizontal' /> </controls:ItemsRepeater.Layout> </controls:ItemsRepeater> </StackPanel> </DataTemplate> </controls:ItemsRepeater> </ScrollViewer> </controls:ItemsRepeaterScrollHost>"); rootRepeater = (ItemsRepeater)scrollhost.FindName("repeater"); scrollViewer = (ScrollViewer)scrollhost.FindName("scrollviewer"); scrollViewer.ViewChanged += (sender, args) => { if (!args.IsIntermediate) { viewChanged.Set(); } }; List <List <int> > items = new List <List <int> >(); for (int i = 0; i < 100; i++) { items.Add(Enumerable.Range(0, 4).ToList()); } rootRepeater.ItemsSource = items; Content = scrollhost; }); // scroll down several times and validate no crash for (int i = 1; i < 5; i++) { IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { scrollViewer.ChangeView(null, i * 200, null); }); Verify.IsTrue(viewChanged.WaitOne(DefaultWaitTimeInMS)); viewChanged.Reset(); } }
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); }); } }
public void ValidateRecycledElementOwnerAffinity() { RunOnUIThread.Execute(() => { ItemsRepeater repeater1 = null; ItemsRepeater repeater2 = null; const int numItems = 10; var dataCollection = new ObservableCollection <int>(Enumerable.Range(0, numItems)); const string recycleKey = "key"; var dataSource = MockItemsSource.CreateDataSource <int>(dataCollection, true); var layout = new StackLayout(); var recyclePool = new RecyclePool(); var itemTemplate = (DataTemplate)XamlReader.Load( @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'> <TextBlock Text='{Binding}' /> </DataTemplate>"); repeater1 = new ItemsRepeater() { ItemsSource = dataSource, Layout = layout, #if BUILD_WINDOWS ItemTemplate = (Windows.UI.Xaml.IElementFactory) new RecyclingElementFactoryDerived() #else ItemTemplate = new RecyclingElementFactoryDerived() #endif { Templates = { { "key", itemTemplate } }, RecyclePool = recyclePool, SelectTemplateIdFunc = (object data, UIElement owner) => recycleKey } }; repeater2 = new ItemsRepeater() { ItemsSource = dataSource, Layout = layout, #if BUILD_WINDOWS ItemTemplate = (Windows.UI.Xaml.IElementFactory) new RecyclingElementFactoryDerived() #else ItemTemplate = new RecyclingElementFactoryDerived() #endif { Templates = { { "key", itemTemplate } }, RecyclePool = recyclePool, SelectTemplateIdFunc = (object data, UIElement owner) => recycleKey } }; var root = new StackPanel(); root.Children.Add(repeater1); root.Children.Add(repeater2); Content = new ItemsRepeaterScrollHost() { Width = 400, Height = 400, ScrollViewer = new ScrollViewer() { Content = root } }; Content.UpdateLayout(); Verify.AreEqual(numItems, VisualTreeHelper.GetChildrenCount(repeater1)); Verify.AreEqual(numItems, VisualTreeHelper.GetChildrenCount(repeater2)); // Throw all the elements into the recycle pool dataCollection.Clear(); Content.UpdateLayout(); for (int i = 0; i < numItems; i++) { var element1 = (FrameworkElement)recyclePool.TryGetElement(recycleKey, repeater1); Verify.AreSame(repeater1, element1.Parent); var element2 = (FrameworkElement)recyclePool.TryGetElement(recycleKey, repeater2); Verify.AreSame(repeater2, element2.Parent); } }); }
public void ValidatePhaseInvokeAndOrdering() { if (!PlatformConfiguration.IsOsVersionGreaterThan(OSVersion.Redstone2)) { Log.Warning("Skipping: GetAvailableSize API is only available in RS3 and above."); return; } ItemsRepeater repeater = null; int numPhases = 6; // 0 to 5 ManualResetEvent buildTreeCompleted = new ManualResetEvent(false); RunOnUIThread.Execute(() => { var itemTemplate = (DataTemplate)XamlReader.Load( @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'> <Button Width='100' Height='100'/> </DataTemplate>"); repeater = new ItemsRepeater() { ItemsSource = Enumerable.Range(0, 10), #if BUILD_WINDOWS ItemTemplate = (Windows.UI.Xaml.IElementFactory) new CustomElementFactory(numPhases), #else ItemTemplate = new CustomElementFactory(numPhases), #endif Layout = new StackLayout(), }; repeater.ElementPrepared += (sender, args) => { if (args.Index == expectedLastRealizedIndex) { Log.Comment("Item 8 Created!"); RepeaterTestHooks.BuildTreeCompleted += (sender1, args1) => { buildTreeCompleted.Set(); }; } }; Content = new ItemsRepeaterScrollHost() { Width = 400, Height = 400, ScrollViewer = new ScrollViewer { Content = repeater } }; // CompositionTarget.Rendering += (sender, args) => { Log.Comment("Rendering"); }; // debugging aid }); if (buildTreeCompleted.WaitOne(TimeSpan.FromMilliseconds(2000))) { RunOnUIThread.Execute(() => { var calls = ElementPhasingManager.ProcessedCalls; Verify.AreEqual(9, calls.Count); calls[0].RemoveAt(0); // Remove the create we did for first measure. foreach (var index in calls.Keys) { var phases = calls[index]; Verify.AreEqual(6, phases.Count); for (int i = 0; i < phases.Count; i++) { Verify.AreEqual(i, phases[i]); } } ElementPhasingManager.ProcessedCalls.Clear(); }); } else { Verify.Fail("Failed on waiting on build tree."); } }
public void ValidateXBindWithoutPhasing() { ItemsRepeater repeater = null; int numPhases = 1; // Just Phase 0 for x:Bind ManualResetEvent ElementLoadedCompleted = new ManualResetEvent(false); RunOnUIThread.Execute(() => { var itemTemplate = (DataTemplate)XamlReader.Load( @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'> <Button Width='100' Height='100'/> </DataTemplate>"); repeater = new ItemsRepeater() { ItemsSource = Enumerable.Range(0, 10), #if BUILD_WINDOWS ItemTemplate = (Windows.UI.Xaml.IElementFactory) new CustomElementFactory(numPhases), #else ItemTemplate = new CustomElementFactory(numPhases), #endif Layout = new StackLayout(), }; repeater.ElementPrepared += (sender, args) => { if (args.Index == expectedLastRealizedIndex) { Log.Comment("Item 8 Created!"); ElementLoadedCompleted.Set(); } }; Content = new ItemsRepeaterScrollHost() { Width = 400, Height = 400, ScrollViewer = new ScrollViewer { Content = repeater } }; }); if (ElementLoadedCompleted.WaitOne(TimeSpan.FromMilliseconds(2000))) { RunOnUIThread.Execute(() => { var calls = ElementPhasingManager.ProcessedCalls; Verify.AreEqual(calls.Count, 9); calls[0].RemoveAt(0); // Remove the create we did for first measure. foreach (var index in calls.Keys) { var phases = calls[index]; Verify.AreEqual(1, phases.Count); // Just phase 0 } ElementPhasingManager.ProcessedCalls.Clear(); }); } else { Verify.Fail("Failed on waiting on build tree."); } }
public void ValidateElementAnimator() { ItemsRepeater repeater = null; ElementAnimatorDerived animator = null; var data = new ObservableCollection <string>(Enumerable.Range(0, 10).Select(i => string.Format("Item #{0}", i))); var renderingEvent = new ManualResetEvent(false); 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>"); CompositionTarget.Rendering += (sender, args) => { renderingEvent.Set(); }; repeater = new ItemsRepeater() { ItemsSource = data, ItemTemplate = elementFactory, }; Content = new ItemsRepeaterScrollHost() { Width = 400, Height = 800, ScrollViewer = new ScrollViewer { Content = repeater } }; }); IdleSynchronizer.Wait(); Verify.IsTrue(renderingEvent.WaitOne(), "Waiting for rendering event"); List <CallInfo> showCalls = new List <CallInfo>(); List <CallInfo> hideCalls = new List <CallInfo>(); List <CallInfo> boundsChangeCalls = new List <CallInfo>(); RunOnUIThread.Execute(() => { animator = new ElementAnimatorDerived() { HasShowAnimationValue = true, HasHideAnimationValue = true, HasBoundsChangeAnimationValue = true, StartShowAnimationFunc = (UIElement element, AnimationContext context) => { showCalls.Add(new CallInfo(repeater.GetElementIndex(element), context)); }, StartHideAnimationFunc = (UIElement element, AnimationContext context) => { hideCalls.Add(new CallInfo(repeater.GetElementIndex(element), context)); }, StartBoundsChangeAnimationFunc = (UIElement element, AnimationContext context, Rect oldBounds, Rect newBounds) => { boundsChangeCalls.Add(new CallInfo(repeater.GetElementIndex(element), context, oldBounds, newBounds)); } }; repeater.Animator = animator; renderingEvent.Reset(); data.Insert(0, "new item"); data.RemoveAt(2); }); Verify.IsTrue(renderingEvent.WaitOne(), "Waiting for rendering event"); IdleSynchronizer.Wait(); Verify.AreEqual(1, showCalls.Count); var call = showCalls[0]; Verify.AreEqual(0, call.Index); Verify.AreEqual(AnimationContext.CollectionChangeAdd, call.Context); Verify.AreEqual(1, hideCalls.Count); call = hideCalls[0]; Verify.AreEqual(-1, call.Index); // not in the repeater anymore Verify.AreEqual(AnimationContext.CollectionChangeRemove, call.Context); Verify.AreEqual(1, boundsChangeCalls.Count); call = boundsChangeCalls[0]; Verify.AreEqual(1, call.Index); Verify.AreEqual(AnimationContext.CollectionChangeAdd | AnimationContext.CollectionChangeRemove, call.Context); Verify.AreEqual(0, call.OldBounds.Y); Verify.AreEqual(50, call.NewBounds.Y); showCalls.Clear(); hideCalls.Clear(); boundsChangeCalls.Clear(); // Hookup just for show animations and validate. RunOnUIThread.Execute(() => { animator.HasShowAnimationValue = true; animator.HasHideAnimationValue = false; animator.HasBoundsChangeAnimationValue = false; renderingEvent.Reset(); data.Insert(0, "new item"); data.RemoveAt(2); }); Verify.IsTrue(renderingEvent.WaitOne(), "Waiting for rendering event"); IdleSynchronizer.Wait(); Verify.AreEqual(1, showCalls.Count); call = showCalls[0]; Verify.AreEqual(0, call.Index); Verify.AreEqual(AnimationContext.CollectionChangeAdd, call.Context); Verify.AreEqual(0, hideCalls.Count); Verify.AreEqual(0, boundsChangeCalls.Count); }
public async Task ValidateXBindWithoutPhasing() { ItemsRepeater repeater = null; int numPhases = 1; // Just Phase 0 for x:Bind bool ElementLoadedCompleted = false; RunOnUIThread.Execute(() => { var itemTemplate = (DataTemplate)XamlReader.Load( @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'> <Button Width='100' Height='100'/> </DataTemplate>"); repeater = new ItemsRepeater() { ItemsSource = Enumerable.Range(0, 10), ItemTemplate = new CustomElementFactory(numPhases), Layout = new StackLayout(), }; repeater.ElementPrepared += (sender, args) => { if (args.Index == expectedLastRealizedIndex) { Log.Comment("Item 8 Created!"); ElementLoadedCompleted = true; } }; Content = new ItemsRepeaterScrollHost() { Width = 400, Height = 400, ScrollViewer = new ScrollViewer { Content = repeater } }; }); await TestServices.WindowHelper.WaitFor(() => ElementLoadedCompleted, 2000); if (ElementLoadedCompleted) { RunOnUIThread.Execute(() => { var calls = ElementPhasingManager.ProcessedCalls; Verify.AreEqual(calls.Count, 9); calls[0].RemoveAt(0); // Remove the create we did for first measure. foreach (var index in calls.Keys) { var phases = calls[index]; Verify.AreEqual(1, phases.Count); // Just phase 0 } ElementPhasingManager.ProcessedCalls.Clear(); }); } else { Verify.Fail("Failed on waiting on build tree."); } }