public void ValidateNullItemsSource() { RunOnUIThread.Execute(() => { string errorMessage = string.Empty; ItemsRepeater repeater = new ItemsRepeater(); try { repeater.GetOrCreateElement(0); } catch (COMException e) { errorMessage = e.Message; } //Make sure that we threw E_FAIL Verify.IsTrue(errorMessage.Contains("ItemSource doesn't have a value")); }); }
public void ValidateNullItemsSource() { RunOnUIThread.Execute(() => { string errorMessage = string.Empty; ItemsRepeater repeater = new ItemsRepeater(); try { repeater.GetOrCreateElement(0); } #if HAS_UNO //WinUI uses COMException here, we use InvalidOperationException instead. catch (InvalidOperationException e) #endif { errorMessage = e.Message; } //Make sure that we threw E_FAIL Verify.IsTrue(errorMessage.Contains("ItemSource doesn't have a value")); }); }
public void CanBringIntoViewElements() { if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5)) { // Note that UIElement.BringIntoViewRequested was added in RS4, and effective viewport was added in RS5 Log.Warning("Skipping since version is less than RS5 and effective viewport feature is not available below RS5"); return; } Scroller scroller = null; ItemsRepeater repeater = null; var rootLoadedEvent = new AutoResetEvent(initialState: false); var viewChangedEvent = new AutoResetEvent(initialState: false); var waitingForIndex = -1; var indexRealized = new AutoResetEvent(initialState: false); var viewChangedOffsets = new List <double>(); RunOnUIThread.Execute(() => { var lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam laoreet erat vel massa rutrum, eget mollis massa vulputate. Vivamus semper augue leo, eget faucibus nulla mattis nec. Donec scelerisque lacus at dui ultricies, eget auctor ipsum placerat. Integer aliquet libero sed nisi eleifend, nec rutrum arcu lacinia. Sed a sem et ante gravida congue sit amet ut augue. Donec quis pellentesque urna, non finibus metus. Proin sed ornare tellus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam laoreet erat vel massa rutrum, eget mollis massa vulputate. Vivamus semper augue leo, eget faucibus nulla mattis nec. Donec scelerisque lacus at dui ultricies, eget auctor ipsum placerat. Integer aliquet libero sed nisi eleifend, nec rutrum arcu lacinia. Sed a sem et ante gravida congue sit amet ut augue. Donec quis pellentesque urna, non finibus metus. Proin sed ornare tellus."; var root = (Grid)XamlReader.Load(TestUtilities.ProcessTestXamlForRepo( @"<Grid 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' xmlns:primitives='using:Microsoft.UI.Xaml.Controls.Primitives'> <Grid.Resources> <controls:StackLayout x:Name='VerticalStackLayout' /> <controls:RecyclingElementFactory x:Key='ElementFactory'> <controls:RecyclingElementFactory.RecyclePool> <controls:RecyclePool /> </controls:RecyclingElementFactory.RecyclePool> <DataTemplate x:Key='ItemTemplate'> <Border Background='LightGray' Margin ='5'> <TextBlock Text='{Binding}' TextWrapping='WrapWholeWords' /> </Border> </DataTemplate> </controls:RecyclingElementFactory> </Grid.Resources> <primitives:Scroller x:Name='Scroller' Width='400' Height='600' ContentOrientation='Vertical' Background='Gray'> <controls:ItemsRepeater x:Name='ItemsRepeater' ItemTemplate='{StaticResource ElementFactory}' Layout='{StaticResource VerticalStackLayout}' HorizontalCacheLength='0' VerticalCacheLength='0' /> </primitives:Scroller> </Grid>")); var elementFactory = (RecyclingElementFactory)root.Resources["ElementFactory"]; scroller = (Scroller)root.FindName("Scroller"); repeater = (ItemsRepeater)root.FindName("ItemsRepeater"); repeater.ElementPrepared += (sender, args) => { Log.Comment($"Realized index: {args.Index} Wating for index {waitingForIndex}"); if (args.Index == waitingForIndex) { indexRealized.Set(); } }; var items = Enumerable.Range(0, 400).Select(i => string.Format("{0}: {1}", i, lorem.Substring(0, 250))); repeater.ItemsSource = items; scroller.ViewChanged += (o, e) => { Log.Comment("Scroller.ViewChanged: VerticalOffset=" + scroller.VerticalOffset); viewChangedOffsets.Add(scroller.VerticalOffset); viewChangedEvent.Set(); }; scroller.BringingIntoView += (o, e) => { Log.Comment("Scroller.BringingIntoView:"); Log.Comment("TargetVerticalOffset=" + e.TargetVerticalOffset); Log.Comment("RequestEventArgs.AnimationDesired=" + e.RequestEventArgs.AnimationDesired); Log.Comment("RequestEventArgs.Handled=" + e.RequestEventArgs.Handled); Log.Comment("RequestEventArgs.VerticalAlignmentRatio=" + e.RequestEventArgs.VerticalAlignmentRatio); Log.Comment("RequestEventArgs.VerticalOffset=" + e.RequestEventArgs.VerticalOffset); Log.Comment("RequestEventArgs.TargetRect=" + e.RequestEventArgs.TargetRect); }; scroller.EffectiveViewportChanged += (o, args) => { Log.Comment("Scroller.EffectiveViewportChanged: VerticalOffset=" + scroller.VerticalOffset); }; root.Loaded += delegate { rootLoadedEvent.Set(); }; Content = root; }); Verify.IsTrue(rootLoadedEvent.WaitOne(DefaultWaitTimeInMS)); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { waitingForIndex = 101; indexRealized.Reset(); repeater.GetOrCreateElement(100).StartBringIntoView(new BringIntoViewOptions { VerticalAlignmentRatio = 0.0 }); repeater.UpdateLayout(); }); Verify.IsTrue(viewChangedEvent.WaitOne(DefaultWaitTimeInMS)); IdleSynchronizer.Wait(); Verify.AreEqual(1, viewChangedOffsets.Count); viewChangedOffsets.Clear(); Verify.IsTrue(indexRealized.WaitOne(DefaultWaitTimeInMS)); ValidateRealizedRange(repeater, 99, 106); RunOnUIThread.Execute(() => { Log.Comment("Scroll into view item 105 (already realized) w/ animation."); waitingForIndex = 99; repeater.TryGetElement(105).StartBringIntoView(new BringIntoViewOptions { VerticalAlignmentRatio = 0.5, AnimationDesired = true }); repeater.UpdateLayout(); }); Verify.IsTrue(viewChangedEvent.WaitOne(DefaultWaitTimeInMS)); IdleSynchronizer.Wait(); Verify.IsLessThanOrEqual(1, viewChangedOffsets.Count); viewChangedOffsets.Clear(); ValidateRealizedRange(repeater, 101, 109); RunOnUIThread.Execute(() => { Log.Comment("Scroll item 0 to the top w/ animation and 0.5 vertical alignment."); waitingForIndex = 1; indexRealized.Reset(); repeater.GetOrCreateElement(0).StartBringIntoView(new BringIntoViewOptions { VerticalAlignmentRatio = 0.5, AnimationDesired = true }); }); Verify.IsTrue(viewChangedEvent.WaitOne(DefaultWaitTimeInMS)); IdleSynchronizer.Wait(); viewChangedOffsets.Clear(); Verify.IsTrue(indexRealized.WaitOne(DefaultWaitTimeInMS)); // Test Reliability fix. If offset is not 0 yet, give // some more time for the animation to settle down. double verticalOffset = 0; RunOnUIThread.Execute(() => { verticalOffset = scroller.VerticalOffset; }); if (verticalOffset != 0) { Verify.IsTrue(viewChangedEvent.WaitOne(DefaultWaitTimeInMS)); IdleSynchronizer.Wait(); viewChangedOffsets.Clear(); } ValidateRealizedRange(repeater, 0, 6); RunOnUIThread.Execute(() => { // You can't align the first group in the middle obviously. Verify.AreEqual(0, scroller.VerticalOffset); Log.Comment("Scroll to item 20."); waitingForIndex = 21; indexRealized.Reset(); repeater.GetOrCreateElement(20).StartBringIntoView(new BringIntoViewOptions { VerticalAlignmentRatio = 0.0 }); repeater.UpdateLayout(); }); Verify.IsTrue(viewChangedEvent.WaitOne(DefaultWaitTimeInMS)); IdleSynchronizer.Wait(); Verify.IsTrue(indexRealized.WaitOne(DefaultWaitTimeInMS)); ValidateRealizedRange(repeater, 19, 26); }