MaterialDesignInXamlToolkit icon indicating copy to clipboard operation
MaterialDesignInXamlToolkit copied to clipboard

Somtimes dialoghost doesn't have focus.

Open Coolava opened this issue 3 years ago • 3 comments

Bug explanation

I clicked the Add fruit button on the DemoApp's dialogs tab Sample1 repeatedly. However, sometimes the focus is not set on the textbox of the Popup Dialog. It appears irregularly. Sometimes it appears after repeating dozens of times, and sometimes it appears from the beginning.

It appears in DemoApp, Sourcecode, and nuget package of 4.6.1 Release.

image

Left is not focused. right is focused.

Version

4.6.1

Coolava avatar Oct 14 '22 00:10 Coolava

https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit/blob/2a38b2c70a5e851bc5b926e0641c1848e719d86b/MaterialDesignThemes.Wpf/DialogHost.cs#L772-L786

In FocusPopup() method, sometimes ui.IsVisible is false. So focusable is null. So focusable.Focus() not excuted. var focusable = child.VisualDepthFirstTraversal().OfType<UIElement>().FirstOrDefault(ui => ui.Focusable && ui.IsVisible);

So I made temporary way wait until isVisible is true.

        /// <summary>
        /// Attempts to focus the content of a popup.
        /// </summary>
        /// <returns>The popup content.</returns>
        internal UIElement? FocusPopup()
        {
            var child = _popup?.Child ?? _popupContentControl;
            if (child is null) return null;

            CommandManager.InvalidateRequerySuggested();

            var focusable = child.VisualDepthFirstTraversal().OfType<UIElement>().FirstOrDefault(ui => ui.Focusable);

            if (focusable is null)
            {
                return null;
            }

            Debug.WriteLine(string.Format("1. IsVisible : {0}", focusable.IsVisible));

            FocusElement(focusable, 50);

            return child;
        }

        /// <summary>
        /// Set focus UIElement.
        /// If IsVisible is false, focus can not be set. So wait for element is visible.
        /// </summary>
        /// <param name="element">UIElemnt to set focus</param>
        /// <param name="retry">Maximum retry number</param>
        /// <param name="counter">current retry counter</param>
        internal void FocusElement(UIElement element, int retry, int counter = 0)
        {
            Debug.WriteLine(string.Format("2. IsVisible : {0,-5}\t Retry counter : {1} ", element.IsVisible, counter));
            if (element.IsVisible is false && counter < retry)
            {
                counter++;
                element.Dispatcher.InvokeAsync(() =>
                {
                    Thread.Sleep(10);
                    FocusElement(element, retry, counter);
                }, DispatcherPriority.Background);
            }
            else
            {
                SetFocus(element);
            }
        }

        /// <summary>
        /// Set focus on UIElement
        /// </summary>
        internal void SetFocus(UIElement element)
        {
            Debug.WriteLine(string.Format("3. IsVisible : {0}", element.IsVisible));

            if (!element.Focus()) return;
            element.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
        }

Coolava avatar Oct 14 '22 05:10 Coolava

@Coolava Have you tried changing the focusable?.Dispatcher.InvokeAsync to focusable?.Dispatcher.BeginInvoke instead, to push it onto the back of the message pump? It seems like a timing issue.

Alternatively, it may be an idea to hook up a Loaded event handler in which the FocusElement() is called.

nicolaihenriksen avatar Oct 14 '22 11:10 nicolaihenriksen

Struggling with the same issue since upgrading to version 4.*. In Version 3.2, the focus was always set correctly.

Talwynox avatar Jun 28 '23 12:06 Talwynox