/// <summary>
        /// Get control inside the specified layout template.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mode">The layout mode in which the control is defined</param>
        /// <param name="name">The 'x:Name' of the control</param>
        /// <returns></returns>
        /// <remarks>The caller must ensure the control is loaded. This is best done from <see cref="FrameworkElement.Loaded"/> event.</remarks>
        public T GetSampleChild <T>(Design mode, string name)
            where T : FrameworkElement
        {
            var presenter = (ContentPresenter)GetTemplateChild($"{mode}ContentPresenter");

            return(VisualTreeHelperEx.GetFirstDescendant <T>(presenter, x => x.Name == name));
        }
Example #2
0
        private void AddNavigationItems(MUXC.NavigationView nv)
        {
            var categories = Assembly.GetExecutingAssembly().DefinedTypes
                             .Where(x => x.Namespace?.StartsWith("Uno.Themes.Samples") == true)
                             .Select(x => new { TypeInfo = x, SamplePageAttribute = x.GetCustomAttribute <SamplePageAttribute>() })
                             .Where(x => x.SamplePageAttribute != null)
                             .Select(x => new Sample(x.SamplePageAttribute, x.TypeInfo.AsType()))
                             .OrderByDescending(x => x.SortOrder.HasValue)
                             .ThenBy(x => x.SortOrder)
                             .ThenBy(x => x.Title)
                             .GroupBy(x => x.Category);

            foreach (var category in categories.OrderBy(x => x.Key))
            {
                var tier = 1;

                var parentItem = default(MUXC.NavigationViewItem);
                if (category.Key != SampleCategory.None)
                {
                    parentItem = new MUXC.NavigationViewItem
                    {
                        Content          = category.Key.GetDescription() ?? category.Key.ToString(),
                        SelectsOnInvoked = false,
                        Style            = (Style)Resources[$"T{tier++}NavigationViewItemStyle"]
                    }.Apply(NavViewItemVisualStateFix);
                    AutomationProperties.SetAutomationId(parentItem, "Section_" + parentItem.Content);

                    nv.MenuItems.Add(parentItem);
                }

                foreach (var sample in category)
                {
                    var item = new MUXC.NavigationViewItem
                    {
                        Content     = sample.Title,
                        DataContext = sample,
                        Style       = (Style)Resources[$"T{tier}NavigationViewItemStyle"]
                    }.Apply(NavViewItemVisualStateFix);
                    AutomationProperties.SetAutomationId(item, "Section_" + item.Content);

                    (parentItem?.MenuItems ?? nv.MenuItems).Add(item);
                }
            }

            void NavViewItemVisualStateFix(MUXC.NavigationViewItem nvi)
            {
                // gallery#107: on uwp and uno, deselecting a NVI by selecting another NVI will leave the former in the "Selected" state
                // to workaround this, we force reset the visual state when IsSelected becomes false
                nvi.RegisterPropertyChangedCallback(MUXC.NavigationViewItemBase.IsSelectedProperty, (s, e) =>
                {
                    if (!nvi.IsSelected)
                    {
                        // depending on the DisplayMode, a NVIP may or may not be used.
                        var nvip = VisualTreeHelperEx.GetFirstDescendant <MUXCP.NavigationViewItemPresenter>(nvi, x => x.Name == "NavigationViewItemPresenter");
                        VisualStateManager.GoToState((Control)nvip ?? nvi, "Normal", true);
                    }
                });
            }
        }
        private double GetRelativeOffset()
        {
#if NETFX_CORE
            // On UWP we can count on finding a ScrollContentPresenter.
            var scp       = VisualTreeHelperEx.GetFirstDescendant <ScrollContentPresenter>(_scrollViewer);
            var content   = scp?.Content as FrameworkElement;
            var transform = _scrollingTabs.TransformToVisual(content);
            return(transform.TransformPoint(new Point(0, 0)).Y - _scrollViewer.VerticalOffset);
#elif __IOS__
            var transform = _scrollingTabs.TransformToVisual(_scrollViewer);
            return(transform.TransformPoint(new Point(0, 0)).Y);
#else
            var transform = _scrollingTabs.TransformToVisual(this);
            return(transform.TransformPoint(new Point(0, 0)).Y - _top.ActualHeight);
#endif
        }
        private static void InstallIncrementalLoadingWorkaround(object sender, RoutedEventArgs _)
        {
            var lv = (ListView)sender;
            var sv = VisualTreeHelperEx.GetFirstDescendant <ScrollViewer>(lv);

            sv.ViewChanged += async(s, e) =>
            {
                if (lv.ItemsSource is not ISupportIncrementalLoading source)
                {
                    return;
                }
                if (lv.Items.Count > 0 && !source.HasMoreItems)
                {
                    return;
                }
                if (GetIsIncrementallyLoading(lv))
                {
                    return;
                }

                // note: for simplicity, we assume the ItemsPanel is stacked vertically

                // try to load more when there is less than half a page;
                // sv.VerticalOffset only represents the top of rendered area,
                // we need another sv.ViewportHeight (or 1.0 after division) to get to the bottom
                if (((sv.ExtentHeight - sv.VerticalOffset) / sv.ViewportHeight) - 1.0 <= 0.5)
                {
                    try
                    {
                        SetIsIncrementallyLoading(lv, true);
                        await source.LoadMoreItemsAsync(1);
                    }
                    catch (Exception ex)
                    {
                        typeof(ListViewExtensions).Log().Error("failed to load more items: ", ex);
                    }
                    finally
                    {
                        SetIsIncrementallyLoading(lv, false);
                    }
                }
            };
        }