private static object?FindNextFocus(
            FocusNavigationDirection focusNavigationDirection,
            XYFocusOptions xyFocusOptions)
        {
            if (focusNavigationDirection == FocusNavigationDirection.None)
            {
                throw new ArgumentOutOfRangeException(nameof(focusNavigationDirection));
            }

            var core = DXamlCore.Current;

            if (core == null)
            {
                throw new InvalidOperationException("XamlCore is not set.");
            }

            FocusManager?focusManager = null;

            if (xyFocusOptions.SearchRoot is DependencyObject searchRoot)
            {
                focusManager = VisualTree.GetFocusManagerForElement(searchRoot);
            }
            else if (core.GetHandle().InitializationType == InitializationType.IslandsOnly)
            {
                // Return error if searchRoot is not valid in islands/ desktop mode
                throw new ArgumentException("The search root must not be null.");
            }
            else
            {
                // For compat reasons, these FocusManager static APIs need to always use the CoreWindow as the
                // ContentRoot, so explicitly return the CoreWindow content root.
                var contentRootCoordinator = core.GetHandle().ContentRootCoordinator;
                var contentRoot            = contentRootCoordinator?.CoreWindowContentRoot;

                if (contentRoot == null)
                {
                    return(null);
                }

                focusManager = contentRoot.FocusManager;
            }

            if (focusManager == null)
            {
                return(null);
            }

            var root  = focusManager.ContentRoot;
            var scale = RootScale.GetRasterizationScaleForContentRoot(root);

            ConvertOptionsRectsToPhysical(scale, xyFocusOptions);

            var candidate = focusManager.FindNextFocus(
                new FindFocusOptions(focusNavigationDirection),
                xyFocusOptions);

            return(candidate);
        }
示例#2
0
 internal static bool UseLayoutRoundingForBorderThickness(FrameworkElement element)
 {
     // Only snap BorderThickness if:
     // 1) LayoutRounding is enabled - prerequisite for any pixel snapping.
     // 2) There is no CornerRadius - we cannot guarantee snapping when there is a CornerRadius.
     // 3) Plateau != 1.0 - this snapping is to ensure that integral values of BorderThickness don't cause subpixel rendering at high plateau.
     // TODO: Remove check for plateau, BorderThickness should be consistently rounded at all plateaus.
     //return (RootScale.GetRasterizationScaleForElement(element) != 1.0f) &&
     //       element.GetUseLayoutRounding() &&
     //       (!HasNonZeroCornerRadius(element.GetCornerRadius()));
     return((RootScale.GetRasterizationScaleForElement(element) != 1.0f) &&
            element.GetUseLayoutRounding() &&
            (!HasNonZeroCornerRadius(element.GetCornerRadius())));
 }
        private static bool TryMoveFocusStatic(
            FocusNavigationDirection focusNavigationDirection,
            FindNextElementOptions?pFocusNavigationOverride,
            ref IAsyncOperation <FocusMovementResult>?asyncOperation,
            bool useAsync)
        {
            DependencyObject?searchRootAsDO = null;
            Rect             hintRect;
            Rect             exclusionRect;
            XYFocusNavigationStrategyOverride navigationStrategyOverride;
            XYFocusOptions xyFocusOptions = new XYFocusOptions();
            var            pIsFocusMoved  = false;

            FindNextElementOptions?options = pFocusNavigationOverride;

            bool ignoreOcclusivity;
            FocusAsyncOperation?spFocusAsyncOperation = null;

            DXamlCore pCore = DXamlCore.Current;

            if (pCore == null)
            {
                throw new InvalidOperationException("XamlCore is not set.");
            }

            FocusManager?focusManager           = null;
            ContentRoot? contentRoot            = null;
            var          contentRootCoordinator = pCore.GetHandle().ContentRootCoordinator;

            if (options != null)
            {
                var searchRoot = options.SearchRoot;
                exclusionRect = options.ExclusionRect;
                hintRect      = options.HintRect;
                navigationStrategyOverride = options.XYFocusNavigationStrategyOverride;
                ignoreOcclusivity          = options.IgnoreOcclusivity;
                searchRootAsDO             = searchRoot as DependencyObject;

                if (searchRootAsDO != null)
                {
                    contentRoot  = VisualTree.GetContentRootForElement(searchRootAsDO);
                    focusManager = contentRoot?.FocusManager;

                    if (focusManager == null)
                    {
                        throw new InvalidOperationException("Search root is not part of the visual tree.");
                    }
                }
                else if (pCore.GetHandle().InitializationType == InitializationType.IslandsOnly)
                {
                    // SearchRoot must exist for islands/ desktop
                    throw new ArgumentException("The search root must not be null.");
                }
                else
                {
                    contentRoot = contentRootCoordinator?.CoreWindowContentRoot;
                }

                // If we are being passed in the public root visual of a XamlRoot as the SearchRoot, then override the SearchRoot to be the RootVisual.
                // This will enable searching through both the public root visual and the popup root. We will also allow Next/Prev.
                bool shouldOverrideSearchRoot =
                    contentRoot != null &&
                    GetAppVisibleXamlRootContent(contentRoot) == searchRootAsDO;

                if (shouldOverrideSearchRoot)
                {
                    searchRootAsDO = contentRoot !.VisualTree.RootElement;
                }
                else
                {
                    if (focusNavigationDirection != FocusNavigationDirection.Up &&
                        focusNavigationDirection != FocusNavigationDirection.Down &&
                        focusNavigationDirection != FocusNavigationDirection.Left &&
                        focusNavigationDirection != FocusNavigationDirection.Right)
                    {
                        throw new ArgumentOutOfRangeException(
                                  "Focus navigation directions Next, Previous, and None " +
                                  "are not supported when using FindNextElementOptions");
                    }
                }

                xyFocusOptions.NavigationStrategyOverride = navigationStrategyOverride;
                xyFocusOptions.IgnoreOcclusivity          = ignoreOcclusivity;

                Rect exclusionRectNative = exclusionRect;
                Rect hintRectNative      = hintRect;

                if (searchRootAsDO != null)
                {
                    xyFocusOptions.SearchRoot = searchRootAsDO;
                }

                if (!exclusionRectNative.IsUniform)
                {
                    xyFocusOptions.ExclusionRect = exclusionRectNative;
                }

                if (!hintRectNative.IsUniform)
                {
                    xyFocusOptions.FocusHintRectangle = hintRectNative;
                }

                if (contentRoot != null)
                {
                    var scale = RootScale.GetRasterizationScaleForContentRoot(contentRoot);
                    ConvertOptionsRectsToPhysical(scale, xyFocusOptions);
                }
            }

            if (focusManager == null)
            {
                // Return error if call is without focus navigation option in islands/ desktop
                if (pCore.GetHandle().InitializationType == InitializationType.IslandsOnly)
                {
                    throw new InvalidOperationException("Focus navigation options must be set for desktop apps.");
                }

                // For compat reasons, these FocusManager static APIs need to always use the CoreWindow as the
                // ContentRoot, so explicitly return the CoreWindow content root.
                if (contentRoot == null)
                {
                    contentRoot = contentRootCoordinator?.CoreWindowContentRoot;
                }
                if (contentRoot == null)
                {
                    return(pIsFocusMoved);
                }

                focusManager = contentRoot.FocusManager;
            }

            FocusMovement movement = new FocusMovement(xyFocusOptions, focusNavigationDirection, null);

            if (useAsync)
            {
                spFocusAsyncOperation = new FocusAsyncOperation(movement.CorrelationId);
                asyncOperation        = spFocusAsyncOperation.CreateAsyncOperation();

                // Async operation is not guaranteed to be released synchronously.
                // Therefore, we let UpdateFocus to handle the responsibility of releasing it.
                // TODO Uno specific: Do not use async operations, only simulated
                // movement.ShouldCompleteAsyncOperation = focusManager.TrySetAsyncOperation(spFocusAsyncOperation);

                if (movement.ShouldCompleteAsyncOperation)
                {
                    //spFocusAsyncOperation.StartOperation();
                }
            }

            FocusMovementResult result = focusManager.FindAndSetNextFocus(movement);

            // TODO Uno specific: Simulate async completion.
            spFocusAsyncOperation?.CoreSetResults(result);
            spFocusAsyncOperation?.CoreFireCompletion();

            // We ignore result.GetHResult() here because this is a "Try" function
            pIsFocusMoved = result.WasMoved;

            // Async operation is not guaranteed to be released synchronously.
            // Therefore, we let UpdateFocus to handle the responsibility of releasing it.
            //spFocusAsyncOperation.Detach();

            return(pIsFocusMoved);
        }