public void ValidateOneScrollerScenario() { if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5)) { Log.Warning("Skipping since version is less than RS5 and effective viewport feature is not available below RS5"); return; } var realizationRects = new List <Rect>(); Scroller scroller = null; var viewChangeCompletedEvent = new AutoResetEvent(false); RunOnUIThread.Execute(() => { var repeater = new ItemsRepeater() { Layout = GetMonitoringLayout(new Size(500, 600), realizationRects), HorizontalCacheLength = 0.0, VerticalCacheLength = 0.0 }; scroller = new Scroller { Child = repeater, Width = 200, Height = 300 }; Content = scroller; Content.UpdateLayout(); Verify.AreEqual(2, realizationRects.Count); Verify.AreEqual(new Rect(0, 0, 0, 0), realizationRects[0]); Verify.AreEqual(new Rect(0, 0, 200, 300), realizationRects[1]); realizationRects.Clear(); scroller.ViewChangeCompleted += (Scroller sender, ScrollerViewChangeCompletedEventArgs args) => { viewChangeCompletedEvent.Set(); }; }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { scroller.ChangeOffsets(new ScrollerChangeOffsetsOptions(0.0, 100.0, ScrollerViewKind.Absolute, ScrollerViewChangeKind.DisableAnimation, ScrollerViewChangeSnapPointRespect.IgnoreSnapPoints)); }); Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS)); RunOnUIThread.Execute(() => { Verify.AreEqual(new Rect(0, 100, 200, 300), realizationRects.Last()); realizationRects.Clear(); viewChangeCompletedEvent.Reset(); scroller.ChangeZoomFactor(new ScrollerChangeZoomFactorOptions(2.0f, ScrollerViewKind.Absolute, Vector2.Zero, ScrollerViewChangeKind.DisableAnimation, ScrollerViewChangeSnapPointRespect.IgnoreSnapPoints)); }); Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS)); RunOnUIThread.Execute(() => { Verify.AreEqual( new Rect(0, 100, 100, 150), realizationRects.Last()); realizationRects.Clear(); }); }
private void CanAddAndRemoveSnapPointsFromAScroller(ScrollSnapPointsAlignment alignment) { Scroller scroller = null; ScrollSnapPoint snapPoint2 = null; RepeatedScrollSnapPoint snapPoint3 = null; RepeatedScrollSnapPoint snapPoint4 = null; RunOnUIThread.Execute(() => { scroller = new Scroller(); ScrollSnapPoint snapPoint1 = new ScrollSnapPoint(snapPointValue: 10, alignment: alignment); snapPoint2 = new ScrollSnapPoint(snapPointValue: 10, alignment: alignment); snapPoint3 = new RepeatedScrollSnapPoint(offset: 10, interval: 10, start: 10, end: 100, alignment: alignment); snapPoint4 = new RepeatedScrollSnapPoint(offset: 100, interval: 10, start: 100, end: 200, alignment: alignment); ZoomSnapPoint snapPoint5 = new ZoomSnapPoint(snapPointValue: 10); scroller.HorizontalSnapPoints.Add(snapPoint1); scroller.VerticalSnapPoints.Add(snapPoint1); scroller.ZoomSnapPoints.Add(snapPoint5); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Verify.AreEqual <int>(1, scroller.HorizontalSnapPoints.Count); Verify.AreEqual <int>(1, scroller.VerticalSnapPoints.Count); Verify.AreEqual <int>(1, scroller.ZoomSnapPoints.Count); scroller.HorizontalSnapPoints.Add(snapPoint2); scroller.HorizontalSnapPoints.Add(snapPoint3); scroller.HorizontalSnapPoints.Add(snapPoint4); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Verify.AreEqual <int>(4, scroller.HorizontalSnapPoints.Count); scroller.HorizontalSnapPoints.Remove(snapPoint2); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Verify.AreEqual <int>(3, scroller.HorizontalSnapPoints.Count); scroller.HorizontalSnapPoints.Remove(snapPoint2); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Verify.AreEqual <int>(3, scroller.HorizontalSnapPoints.Count); scroller.HorizontalSnapPoints.Clear(); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Verify.AreEqual <int>(0, scroller.HorizontalSnapPoints.Count); Verify.AreEqual <int>(1, scroller.VerticalSnapPoints.Count); Verify.AreEqual <int>(1, scroller.ZoomSnapPoints.Count); }); }
public void VerifyDefaultsAndBasicSetting() { NavigationView navView = null; Rectangle footer = null; TextBlock header = null; Setter styleSetter = null; Style hamburgerStyle = null; RunOnUIThread.Execute(() => { footer = new Rectangle(); footer.Height = 40; header = new TextBlock(); header.Text = "Header"; styleSetter = new Setter(); styleSetter.Property = FrameworkElement.MinHeightProperty; styleSetter.Value = "80"; hamburgerStyle = new Style(); navView = new NavigationView(); // Verify Defaults Verify.IsTrue(navView.IsPaneOpen); Verify.AreEqual(641, navView.CompactModeThresholdWidth); Verify.AreEqual(1008, navView.ExpandedModeThresholdWidth); Verify.IsNull(navView.PaneFooter); Verify.IsNull(navView.Header); Verify.IsTrue(navView.IsSettingsVisible); Verify.IsTrue(navView.IsPaneToggleButtonVisible); Verify.IsTrue(navView.IsTitleBarAutoPaddingEnabled); Verify.IsTrue(navView.AlwaysShowHeader); Verify.AreEqual(48, navView.CompactPaneLength); Verify.AreEqual(320, navView.OpenPaneLength); Verify.IsNull(navView.PaneToggleButtonStyle); Verify.AreEqual(0, navView.MenuItems.Count); Verify.AreEqual(NavigationViewDisplayMode.Minimal, navView.DisplayMode); Verify.AreEqual("", navView.PaneTitle); Verify.IsFalse(navView.IsBackEnabled); Verify.AreEqual(NavigationViewBackButtonVisible.Auto, navView.IsBackButtonVisible); // Verify basic setters navView.IsPaneOpen = true; navView.CompactModeThresholdWidth = 500; navView.ExpandedModeThresholdWidth = 1000; navView.PaneFooter = footer; navView.Header = header; navView.IsSettingsVisible = false; navView.IsPaneToggleButtonVisible = false; navView.IsTitleBarAutoPaddingEnabled = false; navView.AlwaysShowHeader = false; navView.CompactPaneLength = 40; navView.OpenPaneLength = 300; navView.PaneToggleButtonStyle = hamburgerStyle; navView.PaneTitle = "ChangedTitle"; navView.IsBackEnabled = true; navView.IsBackButtonVisible = NavigationViewBackButtonVisible.Visible; // TODO(test adding a MenuItem programmatically) }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Verify.IsTrue(navView.IsPaneOpen); Verify.AreEqual(500, navView.CompactModeThresholdWidth); Verify.AreEqual(1000, navView.ExpandedModeThresholdWidth); Verify.AreEqual(footer, navView.PaneFooter); Verify.AreEqual(header, navView.Header); Verify.IsFalse(navView.IsSettingsVisible); Verify.IsFalse(navView.IsPaneToggleButtonVisible); Verify.IsFalse(navView.IsTitleBarAutoPaddingEnabled); Verify.IsFalse(navView.AlwaysShowHeader); Verify.AreEqual(40, navView.CompactPaneLength); Verify.AreEqual(300, navView.OpenPaneLength); Verify.AreEqual(hamburgerStyle, navView.PaneToggleButtonStyle); Verify.AreEqual("ChangedTitle", navView.PaneTitle); Verify.IsTrue(navView.IsBackEnabled); Verify.AreEqual(NavigationViewBackButtonVisible.Visible, navView.IsBackButtonVisible); // Verify nullable values navView.PaneFooter = null; navView.Header = null; navView.PaneToggleButtonStyle = null; }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Verify.IsNull(navView.PaneFooter); Verify.IsNull(navView.Header); Verify.IsNull(navView.PaneToggleButtonStyle); }); }
public void CanGrowCacheBufferWithScrollViewer() { if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5)) { Log.Warning("Skipping since version is less than RS5 and effective viewport is not available below RS5"); return; } ScrollViewer scroller = null; ItemsRepeater repeater = null; var measureRealizationRects = new List <Rect>(); var arrangeRealizationRects = new List <Rect>(); var fullCacheEvent = new ManualResetEvent(initialState: false); RunOnUIThread.Execute(() => { Log.Comment("Preparing the visual tree..."); scroller = new ScrollViewer { Width = 400, Height = 400 }; var layout = new MockVirtualizingLayout { MeasureLayoutFunc = (availableSize, context) => { var ctx = (VirtualizingLayoutContext)context; Log.Comment("MeasureLayout - Rect:" + ctx.RealizationRect); if (measureRealizationRects.Count == 0 || measureRealizationRects.Last() != ctx.RealizationRect) { measureRealizationRects.Add(ctx.RealizationRect); } return(new Size(1000, 2000)); }, ArrangeLayoutFunc = (finalSize, context) => { var ctx = (VirtualizingLayoutContext)context; Log.Comment("ArrangeLayout - Rect:" + ctx.RealizationRect); if (arrangeRealizationRects.Count == 0 || arrangeRealizationRects.Last() != ctx.RealizationRect) { arrangeRealizationRects.Add(ctx.RealizationRect); } if (ctx.RealizationRect.Height == scroller.Height * (repeater.VerticalCacheLength + 1)) { fullCacheEvent.Set(); } return(finalSize); } }; repeater = new ItemsRepeater() { Layout = layout }; scroller.Content = repeater; Content = scroller; }); if (!fullCacheEvent.WaitOne(DefaultWaitTimeInMS)) { Verify.Fail("Cache full size never reached."); } IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { var cacheLength = repeater.VerticalCacheLength; var expectedRealizationWindow = new Rect( -cacheLength / 2 * scroller.Width, -cacheLength / 2 * scroller.Height, (1 + cacheLength) * scroller.Width, (1 + cacheLength) * scroller.Height); Log.Comment("Validate that the realization window reached full size."); Verify.AreEqual(expectedRealizationWindow, measureRealizationRects.Last()); Verify.AreEqual(expectedRealizationWindow, arrangeRealizationRects.Last()); Log.Comment("Validate that the realization window grew by 40 pixels each time during the process."); for (int i = 2; i < measureRealizationRects.Count; ++i) { Verify.AreEqual(-40, measureRealizationRects[i].X - measureRealizationRects[i - 1].X); Verify.AreEqual(-40, measureRealizationRects[i].Y - measureRealizationRects[i - 1].Y); Verify.AreEqual(80, measureRealizationRects[i].Width - measureRealizationRects[i - 1].Width); Verify.AreEqual(80, measureRealizationRects[i].Height - measureRealizationRects[i - 1].Height); Verify.AreEqual(-40, arrangeRealizationRects[i].X - arrangeRealizationRects[i - 1].X); Verify.AreEqual(-40, arrangeRealizationRects[i].Y - arrangeRealizationRects[i - 1].Y); Verify.AreEqual(80, arrangeRealizationRects[i].Width - arrangeRealizationRects[i - 1].Width); Verify.AreEqual(80, arrangeRealizationRects[i].Height - arrangeRealizationRects[i - 1].Height); } }); }
public void ValidateBasicScrollViewerScenario() { if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5)) { Log.Warning("Skipping since version is less than RS5 and effective viewport is not available below RS5"); return; } var realizationRects = new List <Rect>(); var viewChangeCompletedEvent = new AutoResetEvent(false); ScrollViewer scrollViewer = null; ManualResetEvent viewChanged = new ManualResetEvent(false); ManualResetEvent layoutMeasured = new ManualResetEvent(false); RunOnUIThread.Execute(() => { var repeater = new ItemsRepeater() { Layout = GetMonitoringLayout(new Size(500, 600), realizationRects, layoutMeasured), HorizontalCacheLength = 0.0, VerticalCacheLength = 0.0 }; scrollViewer = new ScrollViewer { Content = repeater, Width = 200, Height = 300, HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden, VerticalScrollBarVisibility = ScrollBarVisibility.Hidden, }; scrollViewer.ViewChanged += (sender, args) => { if (!args.IsIntermediate) { Log.Comment("ViewChanged " + scrollViewer.HorizontalOffset + ":" + scrollViewer.VerticalOffset); viewChanged.Set(); } }; Content = scrollViewer; }); Verify.IsTrue(layoutMeasured.WaitOne(), "Did not receive measure on layout"); RunOnUIThread.Execute(() => { // First layout pass will invalidate measure during the first arrange // so that we can get a viewport during the second measure/arrange pass. Verify.AreEqual(new Rect(0, 0, 0, 0), realizationRects[0]); Verify.AreEqual(new Rect(0, 0, 200, 300), realizationRects[1]); realizationRects.Clear(); viewChanged.Reset(); layoutMeasured.Reset(); scrollViewer.ChangeView(null, 100.0, 1.0f, disableAnimation: true); }); IdleSynchronizer.Wait(); Verify.IsTrue(viewChanged.WaitOne(), "Did not receive view changed event"); Verify.IsTrue(layoutMeasured.WaitOne(), "Did not receive measure on layout"); viewChanged.Reset(); layoutMeasured.Reset(); RunOnUIThread.Execute(() => { Verify.AreEqual(new Rect(0, 100, 200, 300), realizationRects.Last()); realizationRects.Clear(); viewChangeCompletedEvent.Reset(); // Max viewport offset is (300, 400). Horizontal viewport offset // is expected to get coerced from 400 to 300. scrollViewer.ChangeView(400, 100.0, 1.0f, disableAnimation: true); }); IdleSynchronizer.Wait(); Verify.IsTrue(viewChanged.WaitOne(), "Did not receive view changed event"); Verify.IsTrue(layoutMeasured.WaitOne(), "Did not receive measure on layout"); viewChanged.Reset(); layoutMeasured.Reset(); RunOnUIThread.Execute(() => { Verify.AreEqual(new Rect(300, 100, 200, 300), realizationRects.Last()); realizationRects.Clear(); viewChangeCompletedEvent.Reset(); scrollViewer.ChangeView(null, null, 2.0f, disableAnimation: true); }); IdleSynchronizer.Wait(); Verify.IsTrue(viewChanged.WaitOne(), "Did not receive view changed event"); Verify.IsTrue(layoutMeasured.WaitOne(), "Did not receive measure on layout"); viewChanged.Reset(); layoutMeasured.Reset(); RunOnUIThread.Execute(() => { Verify.AreEqual(new Rect(150, 50, 100, 150), realizationRects.Last()); realizationRects.Clear(); }); }
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 ValidateOneScrollViewerScenario() { if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5)) { Log.Warning("Skipping since version is less than RS5 and effective viewport is not available below RS5"); return; } var realizationRects = new List <Rect>(); ScrollViewer scrollViewer = null; var viewChangeCompletedEvent = new AutoResetEvent(false); RunOnUIThread.Execute(() => { var repeater = new ItemsRepeater() { Layout = GetMonitoringLayout(new Size(500, 600), realizationRects), HorizontalCacheLength = 0.0, VerticalCacheLength = 0.0 }; scrollViewer = new ScrollViewer { Content = repeater, Width = 200, Height = 300 }; Content = scrollViewer; Content.UpdateLayout(); Verify.AreEqual(2, realizationRects.Count); Verify.AreEqual(new Rect(0, 0, 0, 0), realizationRects[0]); Verify.AreEqual(new Rect(0, 0, 200, 300), realizationRects[1]); realizationRects.Clear(); scrollViewer.ViewChanged += (Object sender, ScrollViewerViewChangedEventArgs args) => { if (!args.IsIntermediate) { viewChangeCompletedEvent.Set(); } }; }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { scrollViewer.ChangeView(0.0, 100.0, null, true); }); Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS)); RunOnUIThread.Execute(() => { Verify.AreEqual(new Rect(0, 100, 200, 300), realizationRects.Last()); realizationRects.Clear(); viewChangeCompletedEvent.Reset(); scrollViewer.ChangeView(null, null, 2.0f, true); }); Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS)); RunOnUIThread.Execute(() => { Verify.AreEqual( new Rect(0, 50, 100, 150), realizationRects.Last()); realizationRects.Clear(); }); }
private void AnchoringWithOffsetCoercion(bool reduceAnchorOffset) { using (ScrollerTestHooksHelper scrollerTestHooksHelper = new ScrollerTestHooksHelper( enableAnchorNotifications: true, enableInteractionSourcesNotifications: true, enableExpressionAnimationStatusNotifications: false)) { Scroller scroller = null; Border anchorElement = null; AutoResetEvent scrollerLoadedEvent = new AutoResetEvent(false); AutoResetEvent scrollerViewChangedEvent = new AutoResetEvent(false); AutoResetEvent scrollerAnchorRequestedEvent = new AutoResetEvent(false); // This test validates that the Scroller accounts for maximum vertical offset (based on viewport and content extent) // when calculating the vertical offset shift for anchoring. The vertical offset cannot exceed content extent - viewport. RunOnUIThread.Execute(() => { Log.Comment("Visual tree setup"); anchorElement = new Border { Width = 100, Height = 100, Background = new SolidColorBrush(Colors.Red), Margin = new Thickness(0, 600, 0, 0), VerticalAlignment = VerticalAlignment.Top }; Grid grid = new Grid(); grid.Children.Add(anchorElement); grid.Width = 200; grid.Height = 1000; grid.Background = new SolidColorBrush(Colors.Gray); scroller = new Scroller { Content = grid, Width = 200, Height = 200 }; scroller.Loaded += (object sender, RoutedEventArgs e) => { Log.Comment("Scroller.Loaded event handler"); scrollerLoadedEvent.Set(); }; scroller.ViewChanged += delegate(Scroller sender, object args) { Log.Comment("ViewChanged - HorizontalOffset={0}, VerticalOffset={1}, ZoomFactor={2}", sender.HorizontalOffset, sender.VerticalOffset, sender.ZoomFactor); if ((reduceAnchorOffset && sender.VerticalOffset == 400) || (!reduceAnchorOffset && sender.VerticalOffset == 500)) { scrollerViewChangedEvent.Set(); } }; scroller.AnchorRequested += delegate(Scroller sender, ScrollerAnchorRequestedEventArgs args) { Log.Comment("Scroller.AnchorRequested event handler. Forcing the red Border to be the Scroller anchor."); args.AnchorElement = anchorElement; scrollerAnchorRequestedEvent.Set(); }; Log.Comment("Setting window content"); MUXControlsTestApp.App.TestContentRoot = scroller; }); WaitForEvent("Waiting for Scroller.Loaded event", scrollerLoadedEvent); IdleSynchronizer.Wait(); ScrollTo(scroller, 0.0, 600.0, AnimationMode.Disabled, SnapPointsMode.Ignore); RunOnUIThread.Execute(() => { Verify.AreEqual(600, scroller.VerticalOffset); Log.Comment("Scroller.Content height is reduced by 300px. Scroller.VerticalOffset is expected to be reduced by 100px (600 -> 500)."); (scroller.Content as Grid).Height = 700; if (reduceAnchorOffset) { Log.Comment("Tracked element is shifted up by 200px within the Scroller.Content (600 -> 400). Anchoring is expected to reduce the VerticalOffset by half of that (500 -> 400)."); anchorElement.Margin = new Thickness(0, 400, 0, 0); } scrollerViewChangedEvent.Reset(); }); WaitForEvent("Waiting for Scroller.ViewChanged event", scrollerViewChangedEvent); WaitForEvent("Waiting for Scroller.AnchorRequested event", scrollerAnchorRequestedEvent); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Verify.AreEqual(reduceAnchorOffset ? 400 : 500, scroller.VerticalOffset); }); } }
// [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()); }); }
private void AnchoringAtAlmostFarEdge(Orientation orientation) { using (ScrollerTestHooksHelper scrollerTestHooksHelper = new ScrollerTestHooksHelper( enableAnchorNotifications: true, enableInteractionSourcesNotifications: true, enableExpressionAnimationStatusNotifications: false)) { Scroller scroller = null; AutoResetEvent scrollerLoadedEvent = new AutoResetEvent(false); RunOnUIThread.Execute(() => { scroller = new Scroller(); SetupDefaultAnchoringUI(orientation, scroller, scrollerLoadedEvent); }); WaitForEvent("Waiting for Loaded event", scrollerLoadedEvent); ZoomTo(scroller, 2.0f, 0.0f, 0.0f, AnimationMode.Disabled, SnapPointsMode.Ignore); double horizontalOffset = 0.0; double verticalOffset = 0.0; RunOnUIThread.Execute(() => { if (orientation == Orientation.Vertical) { verticalOffset = scroller.ExtentHeight * 2.0 - scroller.Height - 1.0; scroller.VerticalAnchorRatio = 1.0; } else { horizontalOffset = scroller.ExtentWidth * 2.0 - scroller.Width - 1.0; scroller.HorizontalAnchorRatio = 1.0; } }); ScrollTo(scroller, horizontalOffset, verticalOffset, AnimationMode.Disabled, SnapPointsMode.Ignore, false /*hookViewChanged*/); RunOnUIThread.Execute(() => { Log.Comment("Inserting child at far edge"); InsertStackPanelChild((scroller.Content as Border).Child as StackPanel, 1 /*operationCount*/, c_defaultAnchoringUIStackPanelChildrenCount /*newIndex*/, 1 /*newCount*/); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Log.Comment("No Scroller offset change expected"); if (orientation == Orientation.Vertical) { Verify.AreEqual(scroller.VerticalOffset, verticalOffset); } else { Verify.AreEqual(scroller.HorizontalOffset, horizontalOffset); } }); } }
private void AnchoringElementWithResizedViewport(Orientation orientation, double viewportSizeChange) { using (ScrollerTestHooksHelper scrollerTestHooksHelper = new ScrollerTestHooksHelper( enableAnchorNotifications: true, enableInteractionSourcesNotifications: true, enableExpressionAnimationStatusNotifications: false)) { Scroller scroller = null; AutoResetEvent scrollerLoadedEvent = new AutoResetEvent(false); AutoResetEvent scrollerViewChangedEvent = new AutoResetEvent(false); RunOnUIThread.Execute(() => { scroller = new Scroller(); SetupDefaultAnchoringUI(orientation, scroller, scrollerLoadedEvent); }); WaitForEvent("Waiting for Loaded event", scrollerLoadedEvent); ZoomTo(scroller, 2.0f, 0.0f, 0.0f, AnimationMode.Disabled, SnapPointsMode.Ignore); double horizontalOffset = 0.0; double verticalOffset = 0.0; RunOnUIThread.Execute(() => { if (orientation == Orientation.Vertical) { verticalOffset = (scroller.ExtentHeight * 2.0 - scroller.Height) / 2.0; scroller.VerticalAnchorRatio = 0.5; } else { horizontalOffset = (scroller.ExtentWidth * 2.0 - scroller.Width) / 2.0; scroller.HorizontalAnchorRatio = 0.5; } }); ScrollTo(scroller, horizontalOffset, verticalOffset, AnimationMode.Disabled, SnapPointsMode.Ignore, false /*hookViewChanged*/); RunOnUIThread.Execute(() => { Log.Comment("Scroller view prior to viewport size change: HorizontalOffset={0}, VerticalOffset={1}, ZoomFactor={2}", scroller.HorizontalOffset, scroller.VerticalOffset, scroller.ZoomFactor); scroller.ViewChanged += delegate(Scroller sender, object args) { Log.Comment("ViewChanged - HorizontalOffset={0}, VerticalOffset={1}, ZoomFactor={2}", sender.HorizontalOffset, sender.VerticalOffset, sender.ZoomFactor); scrollerViewChangedEvent.Set(); }; if (orientation == Orientation.Vertical) { Log.Comment("Changing viewport height"); scroller.Height += viewportSizeChange; } else { Log.Comment("Changing viewport width"); scroller.Width += viewportSizeChange; } }); WaitForEvent("Waiting for Scroller.ViewChanged event", scrollerViewChangedEvent); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Log.Comment("Scroller view after viewport size change: HorizontalOffset={0}, VerticalOffset={1}, ZoomFactor={2}", scroller.HorizontalOffset, scroller.VerticalOffset, scroller.ZoomFactor); Log.Comment("Expecting offset change equal to half the viewport size change"); if (orientation == Orientation.Vertical) { Verify.AreEqual(scroller.VerticalOffset, verticalOffset - viewportSizeChange / 2.0); } else { Verify.AreEqual(scroller.HorizontalOffset, horizontalOffset - viewportSizeChange / 2.0); } }); } }
private void AnchoringAtFarEdgeWhileDecreasingViewport(Orientation orientation) { if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone2)) { Log.Comment("Skipping test on RS1 where InteractionTracker's AdjustPositionXIfGreaterThanThreshold/AdjustPositionYIfGreaterThanThreshold are ineffective in this scenario."); return; } using (ScrollerTestHooksHelper scrollerTestHooksHelper = new ScrollerTestHooksHelper( enableAnchorNotifications: true, enableInteractionSourcesNotifications: true, enableExpressionAnimationStatusNotifications: false)) { Scroller scroller = null; AutoResetEvent scrollerLoadedEvent = new AutoResetEvent(false); AutoResetEvent scrollerViewChangedEvent = new AutoResetEvent(false); RunOnUIThread.Execute(() => { scroller = new Scroller(); SetupDefaultAnchoringUI(orientation, scroller, scrollerLoadedEvent); }); WaitForEvent("Waiting for Loaded event", scrollerLoadedEvent); ZoomTo(scroller, 2.0f, 0.0f, 0.0f, AnimationMode.Disabled, SnapPointsMode.Ignore); double horizontalOffset = 0.0; double verticalOffset = 0.0; RunOnUIThread.Execute(() => { if (orientation == Orientation.Vertical) { verticalOffset = scroller.ExtentHeight * 2.0 - scroller.Height; scroller.VerticalAnchorRatio = 1.0; } else { horizontalOffset = scroller.ExtentWidth * 2.0 - scroller.Width; scroller.HorizontalAnchorRatio = 1.0; } }); ScrollTo(scroller, horizontalOffset, verticalOffset, AnimationMode.Disabled, SnapPointsMode.Ignore, false /*hookViewChanged*/); RunOnUIThread.Execute(() => { scroller.ViewChanged += delegate(Scroller sender, object args) { Log.Comment("ViewChanged - HorizontalOffset={0}, VerticalOffset={1}, ZoomFactor={2}", sender.HorizontalOffset, sender.VerticalOffset, sender.ZoomFactor); scrollerViewChangedEvent.Set(); }; if (orientation == Orientation.Vertical) { Log.Comment("Decreasing viewport height"); scroller.Height -= 100; } else { Log.Comment("Decreasing viewport width"); scroller.Width -= 100; } }); WaitForEvent("Waiting for Scroller.ViewChanged event", scrollerViewChangedEvent); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { if (orientation == Orientation.Vertical) { verticalOffset = scroller.ExtentHeight * 2.0 - scroller.Height; } else { horizontalOffset = scroller.ExtentWidth * 2.0 - scroller.Width; } Log.Comment("Scroller offset change expected"); Verify.AreEqual(scroller.HorizontalOffset, horizontalOffset); Verify.AreEqual(scroller.VerticalOffset, verticalOffset); }); } }
public void TransitionFallbackLogic() { AnimatedIcon animatedIcon = null; var layoutUpdatedEvent = new AutoResetEvent(false); RunOnUIThread.Execute(() => { animatedIcon = new AnimatedIcon(); animatedIcon.Source = new MockIRichAnimatedIconSource(); Content = animatedIcon; Content.UpdateLayout(); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { animatedIcon.LayoutUpdated += AnimatedIcon_LayoutUpdated; AnimatedIcon.SetState(animatedIcon, "a"); Content.UpdateLayout(); }); IdleSynchronizer.Wait(); layoutUpdatedEvent.WaitOne(); RunOnUIThread.Execute(() => { layoutUpdatedEvent.Reset(); AnimatedIcon.SetState(animatedIcon, "b"); Content.UpdateLayout(); }); IdleSynchronizer.Wait(); layoutUpdatedEvent.WaitOne(); RunOnUIThread.Execute(() => { Verify.AreEqual("aTob_Start", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon)); Verify.AreEqual("aTob_End", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon)); layoutUpdatedEvent.Reset(); AnimatedIcon.SetState(animatedIcon, "c"); Content.UpdateLayout(); }); IdleSynchronizer.Wait(); layoutUpdatedEvent.WaitOne(); RunOnUIThread.Execute(() => { Verify.AreEqual("bToc_Start", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon)); // bToc_End is undefined in MockIRichAnimatedIconSource Verify.AreEqual("", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon)); layoutUpdatedEvent.Reset(); AnimatedIcon.SetState(animatedIcon, "d"); Content.UpdateLayout(); }); IdleSynchronizer.Wait(); layoutUpdatedEvent.WaitOne(); RunOnUIThread.Execute(() => { // cTod_Start is undefined in MockIRichAnimatedIconSource Verify.AreEqual("", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon)); Verify.AreEqual("cTod_End", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon)); layoutUpdatedEvent.Reset(); AnimatedIcon.SetState(animatedIcon, "e"); Content.UpdateLayout(); }); IdleSynchronizer.Wait(); layoutUpdatedEvent.WaitOne(); RunOnUIThread.Execute(() => { // dToe_Start and dToe_End are undefined in MockIRichAnimatedIconSource, the first backup is dToe Verify.AreEqual("", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon)); Verify.AreEqual("dToe", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon)); layoutUpdatedEvent.Reset(); AnimatedIcon.SetState(animatedIcon, "f"); Content.UpdateLayout(); }); IdleSynchronizer.Wait(); layoutUpdatedEvent.WaitOne(); RunOnUIThread.Execute(() => { // eTof_Start, eTof_End, and eTof are undefined in MockIRichAnimatedIconSource, the second backup is f Verify.AreEqual("", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon)); Verify.AreEqual("f", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon)); layoutUpdatedEvent.Reset(); AnimatedIcon.SetState(animatedIcon, "b"); Content.UpdateLayout(); }); IdleSynchronizer.Wait(); layoutUpdatedEvent.WaitOne(); RunOnUIThread.Execute(() => { // fTob_Start, fTob_End, fTob and b are all undefined in MockIRichAnimatedIconSource, the third backup is any // marker which ends with the string "Tob_End" Verify.AreEqual("", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon)); Verify.AreEqual("aTob_End", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon)); layoutUpdatedEvent.Reset(); AnimatedIcon.SetState(animatedIcon, "0.12345"); Content.UpdateLayout(); }); IdleSynchronizer.Wait(); layoutUpdatedEvent.WaitOne(); RunOnUIThread.Execute(() => { // bTo0.12345_Start, bTo0.12345_End, bTo0.12345, and 0.12345 are all undefined in MockIRichAnimatedIconSource, and // there are no markers which end with the string "To0.12345_End" so finally we attempt to interpret the state as // a float to get the position to animate to. Verify.AreEqual("", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon)); Verify.AreEqual("0.12345", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon)); layoutUpdatedEvent.Reset(); AnimatedIcon.SetState(animatedIcon, "Failure"); Content.UpdateLayout(); }); IdleSynchronizer.Wait(); layoutUpdatedEvent.WaitOne(); RunOnUIThread.Execute(() => { // 0.12345ToFailure_Start, 0.12345ToFailure_End, 0.12345ToFailure, and Failure are all undefined in MockIRichAnimatedIconSource, and // there are no markers which end with the string "ToFailure_End" and Failure is not a float, so we have failed to find a marker. Verify.AreEqual("", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon)); Verify.AreEqual("0.0", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon)); }); void AnimatedIcon_LayoutUpdated(object sender, object e) { layoutUpdatedEvent.Set(); } }
public void ChangeOffsetsWhileScrollControllersAreAttached() { if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone2)) { Log.Comment("Skipping failing test on RS1."); return; } Scroller scroller = null; Rectangle rectangleScrollerContent = null; CompositionScrollController horizontalScrollController = null; CompositionScrollController verticalScrollController = null; AutoResetEvent loadedEvent = new AutoResetEvent(false); RunOnUIThread.Execute(() => { rectangleScrollerContent = new Rectangle(); scroller = new Scroller(); horizontalScrollController = new CompositionScrollController(); verticalScrollController = new CompositionScrollController(); horizontalScrollController.Orientation = Orientation.Horizontal; horizontalScrollController.LogMessage += (CompositionScrollController sender, string args) => { Log.Comment(args); }; verticalScrollController.LogMessage += (CompositionScrollController sender, string args) => { Log.Comment(args); }; scroller.HorizontalScrollController = horizontalScrollController; scroller.VerticalScrollController = verticalScrollController; SetupUIWithScrollControllers( scroller, rectangleScrollerContent, horizontalScrollController, verticalScrollController, loadedEvent); }); WaitForEvent("Waiting for Loaded event", loadedEvent); RunOnUIThread.Execute(() => { Log.Comment("HorizontalScrollController size={0}, {1}", horizontalScrollController.ActualWidth, horizontalScrollController.ActualHeight); Log.Comment("VerticalScrollController size={0}, {1}", verticalScrollController.ActualWidth, verticalScrollController.ActualHeight); }); IdleSynchronizer.Wait(); Log.Comment("Jump to offsets"); ScrollTo( scroller, (c_defaultUIScrollerContentWidth - c_defaultUIScrollerWidth) / 2.0, (c_defaultUIScrollerContentHeight - c_defaultUIScrollerHeight) / 2.0, AnimationMode.Disabled, SnapPointsMode.Ignore, true /*hookViewChanged*/, (c_defaultUIScrollerContentWidth - c_defaultUIScrollerWidth) / 2.0, (c_defaultUIScrollerContentHeight - c_defaultUIScrollerHeight) / 2.0); Log.Comment("Animate to offsets"); ScrollTo( scroller, (c_defaultUIScrollerContentWidth - c_defaultUIScrollerWidth) / 4.0, (c_defaultUIScrollerContentHeight - c_defaultUIScrollerHeight) / 4.0, AnimationMode.Enabled, SnapPointsMode.Ignore, false /*hookViewChanged*/, (c_defaultUIScrollerContentWidth - c_defaultUIScrollerWidth) / 4.0, (c_defaultUIScrollerContentHeight - c_defaultUIScrollerHeight) / 4.0); Log.Comment("Jump to zoomFactor 2.0"); ZoomTo( scroller, 2.0f, 0.0f, 0.0f, AnimationMode.Disabled, SnapPointsMode.Ignore, false /*hookViewChanged*/); Log.Comment("Animate to zoomFactor 1.5"); ZoomTo( scroller, 1.5f, 0.0f, 0.0f, AnimationMode.Enabled, SnapPointsMode.Ignore, false /*hookViewChanged*/); }
public void VerifyFocusedItemIsRecycledOnCollectionReset() { List <Layout> layouts = new List <Layout>(); RunOnUIThread.Execute(() => { layouts.Add(new MyCustomNonVirtualizingStackLayout()); layouts.Add(new StackLayout()); }); foreach (var layout in layouts) { List <string> items = new List <string> { "item0", "item1", "item2", "item3", "item4", "item5", "item6", "item7", "item8", "item9" }; const int targetIndex = 4; string targetItem = items[targetIndex]; ItemsRepeater repeater = null; RunOnUIThread.Execute(() => { repeater = new ItemsRepeater() { ItemsSource = items, ItemTemplate = CreateDataTemplateWithContent(@"<Button Content='{Binding}'/>"), Layout = layout }; Content = repeater; }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Log.Comment("Setting Focus on item " + targetIndex); Button toFocus = (Button)repeater.TryGetElement(targetIndex); Verify.AreEqual(targetItem, toFocus.Content as string); toFocus.Focus(FocusState.Keyboard); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Log.Comment("Removing focused element from collection"); items.Remove(targetItem); Log.Comment("Reset the collection with an empty list"); repeater.ItemsSource = new List <string>(); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Log.Comment("Verify new elements"); for (int i = 0; i < items.Count; i++) { Button currentButton = (Button)repeater.TryGetElement(i); Verify.IsNull(currentButton); } }); } }
public void ValidateElementClearingOrderFromFlowLayout() { ItemsSourceView dataSource = null; RunOnUIThread.Execute(() => dataSource = new ItemsSourceView(Enumerable.Range(0, 15).ToList())); ScrollViewer scrollViewer = null; var repeater = SetupRepeater(dataSource, null /*layout*/, out scrollViewer); List <int> clearedIndices = new List <int>(); var viewChangedEvent = new ManualResetEvent(false); RunOnUIThread.Execute(() => { scrollViewer.ViewChanged += (sender, args) => { if (!args.IsIntermediate) { viewChangedEvent.Set(); } }; repeater.Layout = new StackLayout(); repeater.ElementPrepared += (sender, args) => { ((FrameworkElement)args.Element).Height = 20; }; repeater.UpdateLayout(); repeater.ElementClearing += (sender, args) => { int index = repeater.GetElementIndex(args.Element); Log.Comment("Clearing.." + index); clearedIndices.Add(index); }; scrollViewer.ChangeView(null, 100.0, null, disableAnimation: true); }); Verify.IsTrue(viewChangedEvent.WaitOne(DefaultWaitTime), "Waiting for ViewChanged."); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { // Validate order is 0, 1, 2, 3 for (int i = 0; i < 4; i++) { Verify.AreEqual(i, clearedIndices[i]); } clearedIndices.Clear(); viewChangedEvent.Reset(); scrollViewer.ChangeView(null, 0.0, null, disableAnimation: true); }); Verify.IsTrue(viewChangedEvent.WaitOne(DefaultWaitTime), "Waiting for ViewChanged."); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { // Validate order is backwards 14, 13, 12, 11 for (int i = 0; i < 4; i++) { Verify.AreEqual(14 - i, clearedIndices[i]); } }); }
private void NestedRepeaterWithDataTemplateScenario(bool disableAnimation) { if (!disableAnimation && PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5)) { Log.Warning("This test is showing consistent issues with not scrolling enough on RS5 and 19H1 when animations are enabled, tracked by microsoft-ui-xaml#779"); return; } // Example of how to include debug tracing in an ApiTests.ItemsRepeater test's output. // using (PrivateLoggingHelper privateLoggingHelper = new PrivateLoggingHelper("Repeater")) // { ItemsRepeater rootRepeater = null; ScrollViewer scrollViewer = null; ManualResetEvent viewChanged = new ManualResetEvent(false); RunOnUIThread.Execute(() => { var anchorProvider = (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}' /> </DataTemplate> <DataTemplate x:Key='GroupTemplate'> <StackPanel> <TextBlock Text='{Binding}' /> <controls:ItemsRepeater ItemTemplate='{StaticResource ItemTemplate}' ItemsSource='{Binding}' VerticalCacheLength='0'/> </StackPanel> </DataTemplate> </controls:ItemsRepeaterScrollHost.Resources> <ScrollViewer x:Name='scrollviewer'> <controls:ItemsRepeater x:Name='rootRepeater' ItemTemplate='{StaticResource GroupTemplate}' VerticalCacheLength='0' /> </ScrollViewer> </controls:ItemsRepeaterScrollHost>"); rootRepeater = (ItemsRepeater)anchorProvider.FindName("rootRepeater"); rootRepeater.SizeChanged += (sender, args) => { Log.Comment($"SizeChanged: Size=({rootRepeater.ActualWidth} x {rootRepeater.ActualHeight})"); }; scrollViewer = (ScrollViewer)anchorProvider.FindName("scrollviewer"); scrollViewer.ViewChanging += (sender, args) => { Log.Comment($"ViewChanging: Next VerticalOffset={args.NextView.VerticalOffset}, Final VerticalOffset={args.FinalView.VerticalOffset}"); }; scrollViewer.ViewChanged += (sender, args) => { Log.Comment($"ViewChanged: VerticalOffset={scrollViewer.VerticalOffset}, IsIntermediate={args.IsIntermediate}"); if (!args.IsIntermediate) { viewChanged.Set(); } }; var itemsSource = new ObservableCollection <ObservableCollection <int> >(); for (int i = 0; i < 100; i++) { itemsSource.Add(new ObservableCollection <int>(Enumerable.Range(0, 5))); } ; rootRepeater.ItemsSource = itemsSource; Content = anchorProvider; }); // scroll down several times to cause recycling of elements for (int i = 1; i < 10; i++) { IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Log.Comment($"Size=({rootRepeater.ActualWidth} x {rootRepeater.ActualHeight})"); Log.Comment($"ChangeView(VerticalOffset={i * 200})"); scrollViewer.ChangeView(null, i * 200, null, disableAnimation); }); Log.Comment("Waiting for view change completion..."); Verify.IsTrue(viewChanged.WaitOne(DefaultWaitTimeInMS)); viewChanged.Reset(); Log.Comment("View change completed"); RunOnUIThread.Execute(() => { Verify.AreEqual(i * 200, scrollViewer.VerticalOffset); }); } // } }
// [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])); } }); }
public void VerifyStoreScenarioCache() { ItemsRepeater rootRepeater = null; RunOnUIThread.Execute(() => { var scrollhost = (ItemsRepeaterScrollHost)XamlReader.Load( @" <controls:ItemsRepeaterScrollHost Width='400' Height='200' 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='100' Width='100'/> </DataTemplate> <DataTemplate x:Key='GroupTemplate'> <StackPanel> <TextBlock Text='{Binding}' /> <controls:ItemsRepeaterScrollHost> <ScrollViewer HorizontalScrollMode='Enabled' VerticalScrollMode='Disabled' HorizontalScrollBarVisibility='Auto' VerticalScrollBarVisibility='Hidden'> <controls:ItemsRepeater ItemTemplate='{StaticResource ItemTemplate}' ItemsSource='{Binding}'> <controls:ItemsRepeater.Layout> <controls:StackLayout Orientation='Horizontal' /> </controls:ItemsRepeater.Layout> </controls:ItemsRepeater> </ScrollViewer> </controls:ItemsRepeaterScrollHost> </StackPanel> </DataTemplate> </controls:ItemsRepeaterScrollHost.Resources> <ScrollViewer x:Name='scrollviewer'> <controls:ItemsRepeater x:Name='rootRepeater' ItemTemplate='{StaticResource GroupTemplate}'/> </ScrollViewer> </controls:ItemsRepeaterScrollHost>"); rootRepeater = (ItemsRepeater)scrollhost.FindName("rootRepeater"); 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; }); IdleSynchronizer.Wait(); // Verify that first items outside the visible range but in the realized range // for the inner of the nested repeaters are realized. RunOnUIThread.Execute(() => { // Group2 will be outside the visible range but within the realized range. var group2 = rootRepeater.TryGetElement(2) as StackPanel; Verify.IsNotNull(group2); var group2Repeater = ((ItemsRepeaterScrollHost)group2.Children[1]).ScrollViewer.Content as ItemsRepeater; Verify.IsNotNull(group2Repeater); Verify.IsNotNull(group2Repeater.TryGetElement(0)); }); }
public void VerifyOverrides() { #if !BUILD_LEAN_MUX_FOR_THE_STORE_APP RatingControl ratingControl = null; PersonPicture personPicture = null; #endif Slider slider = null; Grid root = null; RunOnUIThread.Execute(() => { var appResources = Application.Current.Resources; // 1) Override WinUI defined brush in App.Resources. appResources["RatingControlCaptionForeground"] = new SolidColorBrush(Colors.Orange); // 2) Override system brush used by WinUI ThemeResource. ((ResourceDictionary)appResources.ThemeDictionaries["Light"])["SystemAltHighColor"] = Colors.Green; ((ResourceDictionary)appResources.ThemeDictionaries["Default"])["SystemAltHighColor"] = Colors.Green; ((ResourceDictionary)appResources.ThemeDictionaries["HighContrast"])["SystemColorButtonTextColor"] = Colors.Green; // 3) Override brush name used by a system control appResources["SliderTrackValueFill"] = new SolidColorBrush(Colors.Purple); root = new Grid { Background = new SolidColorBrush(Colors.AntiqueWhite), }; StackPanel panel = new StackPanel { Orientation = Orientation.Vertical }; panel.Children.Add(slider = new Slider()); #if !BUILD_LEAN_MUX_FOR_THE_STORE_APP panel.Children.Add(ratingControl = new RatingControl() { Value = 2 }); panel.Children.Add(personPicture = new PersonPicture()); #endif root.Children.Add(panel); // Add an element over top to prevent stray mouse input from interfering. root.Children.Add(new Button { Background = new SolidColorBrush(Color.FromArgb(30, 0, 255, 0)), HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch }); MUXControlsTestApp.App.TestContentRoot = root; }); IdleSynchronizer.TryWait(); //System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(20)).Wait(); RunOnUIThread.Execute(() => { #if !BUILD_LEAN_MUX_FOR_THE_STORE_APP // 1) Verify that overriding WinUI defined brushes in App.Resources works. Verify.AreEqual(Colors.Orange, ((SolidColorBrush)ratingControl.Foreground).Color, "Verify RatingControlCaptionForeground override in Application.Resources gets picked up by WinUI control"); // 2) Verify that overriding a system color used by a WinUI control works. Verify.AreEqual(Colors.Green, ((SolidColorBrush)personPicture.Foreground).Color, "Verify PersonPictureForegroundThemeBrush (which uses SystemAltHighColor) overridden in Application.Resources gets picked up by WinUI control"); #endif // 3) Verify that overriding a system brush used by a system control works. if (PlatformConfiguration.IsOsVersionGreaterThan(OSVersion.Redstone1)) { // Below code is comment because of bug 19180323 and we expect the code to be enabled again after test case is moved to nuget testapp //Verify.AreEqual(Colors.Purple, ((SolidColorBrush)slider.Foreground).Color, // "Verify Slider (which uses SliderTrackValueFill as its .Foreground) overridden in Application.Resources gets picked up by Slider control"); } else { // Before RS1, we used to reference system brushes directly. } Log.Comment("Setting Window.Current.Content = null"); MUXControlsTestApp.App.TestContentRoot = null; }); IdleSynchronizer.TryWait(); }
public void ValidateTwoScrollViewerScenario() { if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5)) { Log.Warning("Skipping since version is less than RS5 and effective viewport is not available below RS5"); return; } var realizationRects = new List <Rect>(); ScrollViewer horizontalScroller = null; ScrollViewer verticalScroller = null; var horizontalViewChangeCompletedEvent = new AutoResetEvent(false); var verticalViewChangeCompletedEvent = new AutoResetEvent(false); RunOnUIThread.Execute(() => { var repeater = new ItemsRepeater() { Layout = GetMonitoringLayout(new Size(500, 500), realizationRects), HorizontalCacheLength = 0.0, VerticalCacheLength = 0.0 }; horizontalScroller = new ScrollViewer { Content = repeater, HorizontalScrollBarVisibility = ScrollBarVisibility.Auto, VerticalScrollBarVisibility = ScrollBarVisibility.Disabled, HorizontalScrollMode = ScrollMode.Enabled, VerticalScrollMode = ScrollMode.Disabled }; verticalScroller = new ScrollViewer { Content = horizontalScroller, Width = 200, Height = 200 }; Content = verticalScroller; Content.UpdateLayout(); Verify.AreEqual(2, realizationRects.Count); Verify.AreEqual(new Rect(0, 0, 0, 0), realizationRects[0]); Verify.AreEqual(new Rect(0, 0, 200, 200), realizationRects[1]); realizationRects.Clear(); horizontalScroller.ViewChanged += (Object sender, ScrollViewerViewChangedEventArgs args) => { if (!args.IsIntermediate) { horizontalViewChangeCompletedEvent.Set(); } }; verticalScroller.ViewChanged += (Object sender, ScrollViewerViewChangedEventArgs args) => { if (!args.IsIntermediate) { verticalViewChangeCompletedEvent.Set(); } }; }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { verticalScroller.ChangeView(0.0, 100.0, null, true); }); Verify.IsTrue(verticalViewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS)); RunOnUIThread.Execute(() => { Verify.AreEqual(new Rect(0, 100, 200, 200), realizationRects.Last()); realizationRects.Clear(); // Max viewport offset is (300, 300). Horizontal viewport offset // is expected to get coerced from 400 to 300. horizontalScroller.ChangeView(400.0, 100.0, null, true); }); Verify.IsTrue(horizontalViewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS)); RunOnUIThread.Execute(() => { Verify.AreEqual(new Rect(300, 100, 200, 200), realizationRects.Last()); realizationRects.Clear(); }); }
public void CanReplaceSingleItem() { CustomItemsSource dataSource = null; RunOnUIThread.Execute(() => dataSource = new CustomItemsSource(Enumerable.Range(0, 10).ToList())); ScrollViewer scrollViewer = null; ItemsRepeater repeater = null; var viewChangedEvent = new ManualResetEvent(false); int elementsCleared = 0; int elementsPrepared = 0; RunOnUIThread.Execute(() => { repeater = SetupRepeater(dataSource, ref scrollViewer); scrollViewer.ScrollChanged += (sender, args) => { if (args.HorizontalChange != 0 || args.VerticalChange != 0) { viewChangedEvent.Set(); } }; repeater.ElementPrepared += (sender, args) => { elementsPrepared++; }; repeater.ElementClearing += (sender, args) => { elementsCleared++; }; scrollViewer.ChangeView(null, 200, null, true); }); Verify.IsTrue(viewChangedEvent.WaitOne(DefaultWaitTime), "Waiting for ViewChanged."); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { var realized = VerifyRealizedRange(repeater, dataSource); Verify.AreEqual(4, realized); Log.Comment("Replace before realized range."); dataSource.Replace(index: 0, oldCount: 1, newCount: 1, reset: false); repeater.UpdateLayout(); realized = VerifyRealizedRange(repeater, dataSource); Verify.AreEqual(4, realized); Log.Comment("Replace in realized range."); elementsPrepared = 0; elementsCleared = 0; dataSource.Replace(index: 2, oldCount: 1, newCount: 1, reset: false); repeater.UpdateLayout(); Verify.AreEqual(1, elementsPrepared); Verify.AreEqual(1, elementsCleared); realized = VerifyRealizedRange(repeater, dataSource); Verify.AreEqual(4, realized); Log.Comment("Replace after realized range"); dataSource.Replace(index: 8, oldCount: 1, newCount: 1, reset: false); repeater.UpdateLayout(); realized = VerifyRealizedRange(repeater, dataSource); Verify.AreEqual(4, realized); }); }
public void CanBringIntoViewElements() { if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5)) { Log.Warning("Skipping since version is less than RS5 and effective viewport is not available below RS5"); return; } if (!PlatformConfiguration.IsOsVersionGreaterThan(OSVersion.Redstone3)) { Log.Warning("Skipping CanBringIntoViewElements because UIElement.BringIntoViewRequested was added in RS4."); return; } ScrollViewer scroller = null; ItemsRepeater repeater = null; var rootLoadedEvent = new AutoResetEvent(initialState: false); var effectiveViewChangeCompletedEvent = new AutoResetEvent(initialState: false); var viewChangeCompletedEvent = 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'> <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> <ScrollViewer x:Name='Scroller' Width='400' Height='600' Background='Gray'> <controls:ItemsRepeater x:Name='ItemsRepeater' ItemTemplate='{StaticResource ElementFactory}' Layout='{StaticResource VerticalStackLayout}' HorizontalCacheLength='0' VerticalCacheLength='0' /> </ScrollViewer> </Grid>")); var elementFactory = (RecyclingElementFactory)root.Resources["ElementFactory"]; scroller = (ScrollViewer)root.FindName("Scroller"); repeater = (ItemsRepeater)root.FindName("ItemsRepeater"); 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("ViewChanged: " + scroller.VerticalOffset); viewChangedOffsets.Add(scroller.VerticalOffset); if (!e.IsIntermediate) { viewChangeCompletedEvent.Set(); } }; scroller.EffectiveViewportChanged += (o, args) => { effectiveViewChangeCompletedEvent.Set(); }; Content = root; root.Loaded += delegate { rootLoadedEvent.Set(); }; }); Verify.IsTrue(rootLoadedEvent.WaitOne(DefaultWaitTimeInMS)); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { repeater.GetOrCreateElement(100).StartBringIntoView(); repeater.UpdateLayout(); }); Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS)); IdleSynchronizer.Wait(); Verify.AreEqual(1, viewChangedOffsets.Count); viewChangedOffsets.Clear(); ValidateRealizedRange(repeater, 99, 106); RunOnUIThread.Execute(() => { Log.Comment("Scroll into view item 105 (already realized) w/ animation."); repeater.TryGetElement(105).StartBringIntoView(new BringIntoViewOptions { VerticalAlignmentRatio = 0.5, AnimationDesired = true }); repeater.UpdateLayout(); }); Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS)); IdleSynchronizer.Wait(); Verify.IsLessThanOrEqual(1, viewChangedOffsets.Count); viewChangedOffsets.Clear(); ValidateRealizedRange(repeater, 99, 106); RunOnUIThread.Execute(() => { Log.Comment("Scroll item 0 to the top w/ animation and 0.5 vertical alignment."); repeater.GetOrCreateElement(0).StartBringIntoView(new BringIntoViewOptions { VerticalAlignmentRatio = 0.5, AnimationDesired = true }); repeater.UpdateLayout(); }); Verify.IsTrue(viewChangeCompletedEvent.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."); repeater.GetOrCreateElement(20).StartBringIntoView(new BringIntoViewOptions { VerticalAlignmentRatio = 0.0 }); repeater.UpdateLayout(); }); Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS)); IdleSynchronizer.Wait(); ValidateRealizedRange(repeater, 19, 26); }
private void ViewportHeight( bool isScrollerParentSizeSet, bool isScrollerParentMaxSizeSet, VerticalAlignment scrollerVerticalAlignment, double scrollerContentHeight) { Log.Comment($"ViewportHeight test case - isScrollerParentSizeSet: {isScrollerParentSizeSet}, isScrollerParentMaxSizeSet: {isScrollerParentMaxSizeSet}, scrollerVerticalAlignment: {scrollerVerticalAlignment}, scrollerContentHeight: {scrollerContentHeight}"); Border border = null; Scroller scroller = null; StackPanel stackPanel = null; Rectangle rectangle = null; AutoResetEvent borderLoadedEvent = new AutoResetEvent(false); RunOnUIThread.Execute(() => { rectangle = new Rectangle() { Width = 30, Height = scrollerContentHeight }; stackPanel = new StackPanel() { BorderThickness = new Thickness(5), Margin = new Thickness(7), VerticalAlignment = VerticalAlignment.Top }; stackPanel.Children.Add(rectangle); scroller = new Scroller() { Content = stackPanel, ContentOrientation = ContentOrientation.Vertical, VerticalAlignment = scrollerVerticalAlignment }; border = new Border() { BorderThickness = new Thickness(2), Margin = new Thickness(3), VerticalAlignment = VerticalAlignment.Center, Child = scroller }; if (isScrollerParentSizeSet) { border.Width = 300.0; border.Height = 200.0; } if (isScrollerParentMaxSizeSet) { border.MaxWidth = 300.0; border.MaxHeight = 200.0; } border.Loaded += (object sender, RoutedEventArgs e) => { Log.Comment("Border.Loaded event handler"); borderLoadedEvent.Set(); }; Log.Comment("Setting window content"); MUXControlsTestApp.App.TestContentRoot = border; }); WaitForEvent("Waiting for Border.Loaded event", borderLoadedEvent); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { double expectedViewportHeight = rectangle.Height + stackPanel.BorderThickness.Top + stackPanel.BorderThickness.Bottom + stackPanel.Margin.Top + stackPanel.Margin.Bottom; double borderChildAvailableHeight = border.ActualHeight - border.BorderThickness.Top - border.BorderThickness.Bottom; if (expectedViewportHeight > borderChildAvailableHeight || scrollerVerticalAlignment == VerticalAlignment.Stretch) { expectedViewportHeight = borderChildAvailableHeight; } Log.Comment($"border.ActualWidth: {border.ActualWidth}, border.ActualHeight: {border.ActualHeight}"); Log.Comment($"Checking ViewportWidth - scroller.ViewportWidth: {scroller.ViewportWidth}, scroller.ActualWidth: {scroller.ActualWidth}"); Verify.AreEqual(scroller.ViewportWidth, scroller.ActualWidth); Log.Comment($"Checking ViewportHeight - expectedViewportHeight: {expectedViewportHeight}, scroller.ViewportHeight: {scroller.ViewportHeight}, scroller.ActualHeight: {scroller.ActualHeight}"); Verify.AreEqual(scroller.ViewportHeight, expectedViewportHeight); Verify.AreEqual(scroller.ViewportHeight, scroller.ActualHeight); }); }
public void CanShareSnapPointsInMultipleCollections() { Scroller scroller1 = null; Scroller scroller2 = null; Scroller scroller3 = null; ScrollSnapPoint scrollSnapPoint1 = null; ScrollSnapPoint scrollSnapPoint2 = null; ScrollSnapPoint scrollSnapPoint3 = null; RepeatedScrollSnapPoint repeatedScrollSnapPoint1 = null; RepeatedScrollSnapPoint repeatedScrollSnapPoint2 = null; RepeatedScrollSnapPoint repeatedScrollSnapPoint3 = null; ZoomSnapPoint zoomSnapPoint1 = null; ZoomSnapPoint zoomSnapPoint2 = null; ZoomSnapPoint zoomSnapPoint3 = null; RunOnUIThread.Execute(() => { scroller1 = new Scroller(); scroller2 = new Scroller(); scroller3 = new Scroller(); scrollSnapPoint1 = new ScrollSnapPoint(snapPointValue: 10, alignment: ScrollSnapPointsAlignment.Near); scrollSnapPoint2 = new ScrollSnapPoint(snapPointValue: 20, alignment: ScrollSnapPointsAlignment.Near); scrollSnapPoint3 = new ScrollSnapPoint(snapPointValue: 30, alignment: ScrollSnapPointsAlignment.Near); repeatedScrollSnapPoint1 = new RepeatedScrollSnapPoint(offset: 10, interval: 10, start: 10, end: 100, alignment: ScrollSnapPointsAlignment.Near); repeatedScrollSnapPoint2 = new RepeatedScrollSnapPoint(offset: 200, interval: 10, start: 110, end: 200, alignment: ScrollSnapPointsAlignment.Near); repeatedScrollSnapPoint3 = new RepeatedScrollSnapPoint(offset: 300, interval: 10, start: 210, end: 300, alignment: ScrollSnapPointsAlignment.Near); zoomSnapPoint1 = new ZoomSnapPoint(snapPointValue: 1); zoomSnapPoint2 = new ZoomSnapPoint(snapPointValue: 2); zoomSnapPoint3 = new ZoomSnapPoint(snapPointValue: 3); scroller1.HorizontalSnapPoints.Add(scrollSnapPoint1); scroller1.HorizontalSnapPoints.Add(scrollSnapPoint2); scroller1.VerticalSnapPoints.Add(scrollSnapPoint1); scroller1.VerticalSnapPoints.Add(scrollSnapPoint3); scroller2.HorizontalSnapPoints.Add(repeatedScrollSnapPoint1); scroller2.HorizontalSnapPoints.Add(repeatedScrollSnapPoint2); scroller2.VerticalSnapPoints.Add(repeatedScrollSnapPoint1); scroller2.VerticalSnapPoints.Add(repeatedScrollSnapPoint3); scroller1.ZoomSnapPoints.Add(zoomSnapPoint1); scroller1.ZoomSnapPoints.Add(zoomSnapPoint2); scroller2.ZoomSnapPoints.Add(zoomSnapPoint1); scroller2.ZoomSnapPoints.Add(zoomSnapPoint3); scroller3.HorizontalSnapPoints.Add(scrollSnapPoint1); scroller3.HorizontalSnapPoints.Add(scrollSnapPoint1); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Vector2 horizontalScrollSnapPoint11ApplicableZone = ScrollerTestHooks.GetHorizontalSnapPointActualApplicableZone(scroller1, scrollSnapPoint1); Vector2 verticalScrollSnapPoint11ApplicableZone = ScrollerTestHooks.GetVerticalSnapPointActualApplicableZone(scroller1, scrollSnapPoint1); Log.Comment("horizontalScrollSnapPoint11ApplicableZone=" + horizontalScrollSnapPoint11ApplicableZone.ToString()); Log.Comment("verticalScrollSnapPoint11ApplicableZone=" + verticalScrollSnapPoint11ApplicableZone.ToString()); Vector2 horizontalScrollSnapPoint21ApplicableZone = ScrollerTestHooks.GetHorizontalSnapPointActualApplicableZone(scroller2, repeatedScrollSnapPoint1); Vector2 verticalScrollSnapPoint21ApplicableZone = ScrollerTestHooks.GetVerticalSnapPointActualApplicableZone(scroller2, repeatedScrollSnapPoint1); Log.Comment("horizontalScrollSnapPoint21ApplicableZone=" + horizontalScrollSnapPoint21ApplicableZone.ToString()); Log.Comment("verticalScrollSnapPoint21ApplicableZone=" + verticalScrollSnapPoint21ApplicableZone.ToString()); Vector2 zoomSnapPoint11ApplicableZone = ScrollerTestHooks.GetZoomSnapPointActualApplicableZone(scroller1, zoomSnapPoint1); Vector2 zoomSnapPoint21ApplicableZone = ScrollerTestHooks.GetZoomSnapPointActualApplicableZone(scroller2, zoomSnapPoint1); Log.Comment("zoomSnapPoint11ApplicableZone=" + zoomSnapPoint11ApplicableZone.ToString()); Log.Comment("zoomSnapPoint21ApplicableZone=" + zoomSnapPoint21ApplicableZone.ToString()); int combinationCount11 = ScrollerTestHooks.GetHorizontalSnapPointCombinationCount(scroller1, scrollSnapPoint1); int combinationCount31 = ScrollerTestHooks.GetHorizontalSnapPointCombinationCount(scroller3, scrollSnapPoint1); Log.Comment("combinationCount11=" + combinationCount11); Log.Comment("combinationCount31=" + combinationCount31); Log.Comment("Expecting different applicable zones for ScrollSnapPoint in horizontal and vertical collections"); Verify.AreEqual <float>(15.0f, horizontalScrollSnapPoint11ApplicableZone.Y); Verify.AreEqual <float>(20.0f, verticalScrollSnapPoint11ApplicableZone.Y); Log.Comment("Expecting identical applicable zones for RepeatedScrollSnapPoint in horizontal and vertical collections"); Verify.AreEqual <float>(10.0f, horizontalScrollSnapPoint21ApplicableZone.X); Verify.AreEqual <float>(10.0f, verticalScrollSnapPoint21ApplicableZone.X); Verify.AreEqual <float>(100.0f, horizontalScrollSnapPoint21ApplicableZone.Y); Verify.AreEqual <float>(100.0f, verticalScrollSnapPoint21ApplicableZone.Y); Log.Comment("Expecting different applicable zones for ZoomSnapPoint in two zoom collections"); Verify.AreEqual <float>(1.5f, zoomSnapPoint11ApplicableZone.Y); Verify.AreEqual <float>(2.0f, zoomSnapPoint21ApplicableZone.Y); Log.Comment("Expecting different combination counts for ScrollSnapPoint in two horizontal collections"); Verify.AreEqual <int>(0, combinationCount11); Verify.AreEqual <int>(1, combinationCount31); }); }
public void BasicMargin() { if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone2)) { Log.Comment("Skipping test on RS1."); return; } const double c_Margin = 50.0; Scroller scroller = null; Rectangle rectangleScrollerContent = null; AutoResetEvent scrollerLoadedEvent = new AutoResetEvent(false); RunOnUIThread.Execute(() => { rectangleScrollerContent = new Rectangle(); scroller = new Scroller(); SetupDefaultUI(scroller, rectangleScrollerContent, scrollerLoadedEvent); }); WaitForEvent("Waiting for Loaded event", scrollerLoadedEvent); RunOnUIThread.Execute(() => { Log.Comment("Adding positive Margin to Scroller.Content"); rectangleScrollerContent.Margin = new Thickness(c_Margin); }); // Try to jump beyond maximum offsets ScrollTo( scroller, c_defaultUIScrollerContentWidth + 2 * c_Margin - c_defaultUIScrollerWidth + 10.0, c_defaultUIScrollerContentHeight + 2 * c_Margin - c_defaultUIScrollerHeight + 10.0, AnimationMode.Disabled, SnapPointsMode.Ignore, hookViewChanged: true, isAnimationsEnabledOverride: null, c_defaultUIScrollerContentWidth + 2 * c_Margin - c_defaultUIScrollerWidth, c_defaultUIScrollerContentHeight + 2 * c_Margin - c_defaultUIScrollerHeight); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Log.Comment("Adding negative Margin to Scroller.Content"); rectangleScrollerContent.Margin = new Thickness(-c_Margin); }); // Try to jump beyond maximum offsets ScrollTo( scroller, c_defaultUIScrollerContentWidth - 2 * c_Margin - c_defaultUIScrollerWidth + 10.0, c_defaultUIScrollerContentHeight - 2 * c_Margin - c_defaultUIScrollerHeight + 10.0, AnimationMode.Disabled, SnapPointsMode.Ignore, hookViewChanged: false, isAnimationsEnabledOverride: null, c_defaultUIScrollerContentWidth - 2 * c_Margin - c_defaultUIScrollerWidth, c_defaultUIScrollerContentHeight - 2 * c_Margin - c_defaultUIScrollerHeight); }
public void VerifySingleSelection() { string navItemPresenter1CurrentState = string.Empty; string navItemPresenter2CurrentState = string.Empty; NavigationView navView = null; NavigationViewItem menuItem1 = null; NavigationViewItem menuItem2 = null; RunOnUIThread.Execute(() => { navView = new NavigationView(); Content = navView; menuItem1 = new NavigationViewItem(); menuItem2 = new NavigationViewItem(); menuItem1.Content = "Item 1"; menuItem2.Content = "Item 2"; navView.MenuItems.Add(menuItem1); navView.MenuItems.Add(menuItem2); navView.Width = 1008; // forces the control into Expanded mode so that the menu renders Content.UpdateLayout(); var menuItemLayoutRoot = VisualTreeHelper.GetChild(menuItem1, 0) as FrameworkElement; var navItemPresenter = VisualTreeHelper.GetChild(menuItemLayoutRoot, 0) as FrameworkElement; var navItemPresenterLayoutRoot = VisualTreeHelper.GetChild(navItemPresenter, 0) as FrameworkElement; var statesGroups = VisualStateManager.GetVisualStateGroups(navItemPresenterLayoutRoot); foreach (var visualStateGroup in statesGroups) { Log.Comment($"VisualStateGroup1: Name={visualStateGroup.Name}, CurrentState={visualStateGroup.CurrentState.Name}"); visualStateGroup.CurrentStateChanged += (object sender, VisualStateChangedEventArgs e) => { Log.Comment($"VisualStateChangedEventArgs1: Name={e.Control.Name}, OldState={e.OldState.Name}, NewState={e.NewState.Name}"); navItemPresenter1CurrentState = e.NewState.Name; }; } menuItemLayoutRoot = VisualTreeHelper.GetChild(menuItem2, 0) as FrameworkElement; navItemPresenter = VisualTreeHelper.GetChild(menuItemLayoutRoot, 0) as FrameworkElement; navItemPresenterLayoutRoot = VisualTreeHelper.GetChild(navItemPresenter, 0) as FrameworkElement; statesGroups = VisualStateManager.GetVisualStateGroups(navItemPresenterLayoutRoot); foreach (var visualStateGroup in statesGroups) { Log.Comment($"VisualStateGroup2: Name={visualStateGroup.Name}, CurrentState={visualStateGroup.CurrentState.Name}"); visualStateGroup.CurrentStateChanged += (object sender, VisualStateChangedEventArgs e) => { Log.Comment($"VisualStateChangedEventArgs2: Name={e.Control.Name}, OldState={e.OldState.Name}, NewState={e.NewState.Name}"); navItemPresenter2CurrentState = e.NewState.Name; }; } Verify.IsFalse(menuItem1.IsSelected); Verify.IsFalse(menuItem2.IsSelected); Verify.AreEqual(null, navView.SelectedItem); menuItem1.IsSelected = true; Content.UpdateLayout(); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Verify.AreEqual("Selected", navItemPresenter1CurrentState); Verify.AreEqual(string.Empty, navItemPresenter2CurrentState); Verify.IsTrue(menuItem1.IsSelected); Verify.IsFalse(menuItem2.IsSelected); Verify.AreEqual(menuItem1, navView.SelectedItem); menuItem2.IsSelected = true; Content.UpdateLayout(); }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { Verify.AreEqual("Normal", navItemPresenter1CurrentState); Verify.AreEqual("Selected", navItemPresenter2CurrentState); Verify.IsTrue(menuItem2.IsSelected); Verify.IsFalse(menuItem1.IsSelected, "MenuItem1 should have been deselected when MenuItem2 was selected"); Verify.AreEqual(menuItem2, navView.SelectedItem); }); }
public void VerifyCurrentAnchor() { if (PlatformConfiguration.IsDebugBuildConfiguration()) { // Test is failing in chk configuration due to: // Bug #1726 Test Failure: RepeaterTests.VerifyCurrentAnchor Log.Warning("Skipping test for Debug builds."); return; } 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); }); } }
private NavigationView SetupNavigationViewScrolling(NavigationViewPaneDisplayMode paneDisplayMode = NavigationViewPaneDisplayMode.Auto) { NavigationView navView = null; RunOnUIThread.Execute(() => { navView = new NavigationView(); navView.MenuItems.Add(new NavigationViewItem() { Content = "Item #1", Icon = new SymbolIcon(Symbol.Undo) }); navView.MenuItems.Add(new NavigationViewItem() { Content = "Item #2", Icon = new SymbolIcon(Symbol.Cut) }); navView.MenuItems.Add(new NavigationViewItemHeader() { Content = "Item #3" }); navView.MenuItems.Add(new NavigationViewItem() { Content = "Item #4", Icon = new SymbolIcon(Symbol.Cut) }); navView.MenuItems.Add(new NavigationViewItem() { Content = "Item #5", Icon = new SymbolIcon(Symbol.Cut) }); navView.MenuItems.Add(new NavigationViewItemSeparator()); navView.MenuItems.Add(new NavigationViewItem() { Content = "Item #7", Icon = new SymbolIcon(Symbol.Cut) }); navView.MenuItems.Add(new NavigationViewItem() { Content = "Item #8", Icon = new SymbolIcon(Symbol.Cut) }); navView.MenuItems.Add(new NavigationViewItem() { Content = "Item #9", Icon = new SymbolIcon(Symbol.Cut) }); navView.MenuItems.Add(new NavigationViewItem() { Content = "Item #10", Icon = new SymbolIcon(Symbol.Cut) }); navView.MenuItems.Add(new NavigationViewItemHeader() { Content = "Item #11" }); navView.MenuItems.Add(new NavigationViewItem() { Content = "Item #12", Icon = new SymbolIcon(Symbol.Cut) }); navView.MenuItems.Add(new NavigationViewItem() { Content = "Item #13", Icon = new SymbolIcon(Symbol.Cut) }); navView.MenuItems.Add(new NavigationViewItemSeparator()); navView.MenuItems.Add(new NavigationViewItem() { Content = "Item #15", Icon = new SymbolIcon(Symbol.Cut) }); navView.IsBackButtonVisible = NavigationViewBackButtonVisible.Visible; navView.IsSettingsVisible = true; navView.PaneDisplayMode = paneDisplayMode; navView.OpenPaneLength = 120.0; navView.ExpandedModeThresholdWidth = 600.0; navView.CompactModeThresholdWidth = 400.0; navView.Width = 800.0; navView.Height = 600.0; navView.Content = "This test should have enough NavigationViewItems to scroll."; Content = navView; Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().TryEnterFullScreenMode(); }); IdleSynchronizer.Wait(); return(navView); }
public void ValidateTwoScrollersScenario() { if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5)) { Log.Warning("Skipping since version is less than RS5 and effective viewport feature is not available below RS5"); return; } var realizationRects = new List <Rect>(); Scroller horizontalScroller = null; Scroller verticalScroller = null; var horizontalViewChangeCompletedEvent = new AutoResetEvent(false); var verticalViewChangeCompletedEvent = new AutoResetEvent(false); RunOnUIThread.Execute(() => { var repeater = new ItemsRepeater() { Layout = GetMonitoringLayout(new Size(500, 500), realizationRects), HorizontalCacheLength = 0.0, VerticalCacheLength = 0.0 }; horizontalScroller = new Scroller { Child = repeater, IsChildAvailableHeightConstrained = true }; // Placing a Grid in between two Scroller controls to avoid // unsupported combined use of facades and ElementCompositionPreview. var grid = new Grid(); grid.Children.Add(horizontalScroller); verticalScroller = new Scroller { Child = grid, Width = 200, Height = 200, IsChildAvailableWidthConstrained = true }; Content = verticalScroller; Content.UpdateLayout(); Verify.AreEqual(2, realizationRects.Count); Verify.AreEqual(new Rect(0, 0, 0, 0), realizationRects[0]); Verify.AreEqual(new Rect(0, 0, 200, 200), realizationRects[1]); realizationRects.Clear(); horizontalScroller.ViewChangeCompleted += (Scroller sender, ScrollerViewChangeCompletedEventArgs args) => { horizontalViewChangeCompletedEvent.Set(); }; verticalScroller.ViewChangeCompleted += (Scroller sender, ScrollerViewChangeCompletedEventArgs args) => { verticalViewChangeCompletedEvent.Set(); }; }); IdleSynchronizer.Wait(); RunOnUIThread.Execute(() => { verticalScroller.ChangeOffsets(new ScrollerChangeOffsetsOptions(0.0, 100.0, ScrollerViewKind.Absolute, ScrollerViewChangeKind.DisableAnimation, ScrollerViewChangeSnapPointRespect.IgnoreSnapPoints)); }); Verify.IsTrue(verticalViewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS)); RunOnUIThread.Execute(() => { Verify.AreEqual(new Rect(0, 100, 200, 200), realizationRects.Last()); realizationRects.Clear(); // Max viewport offset is (300, 300). Horizontal viewport offset // is expected to get coerced from 400 to 300. horizontalScroller.ChangeOffsets(new ScrollerChangeOffsetsOptions(400.0, 100.0, ScrollerViewKind.Absolute, ScrollerViewChangeKind.DisableAnimation, ScrollerViewChangeSnapPointRespect.IgnoreSnapPoints)); }); Verify.IsTrue(horizontalViewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS)); RunOnUIThread.Execute(() => { Verify.AreEqual(new Rect(300, 100, 200, 200), realizationRects.Last()); realizationRects.Clear(); }); }