MaterialDesignInXAML / MaterialDesignInXamlToolkit

Google's Material Design in XAML & WPF, for C# & VB.Net.
http://materialdesigninxaml.net
MIT License
15.06k stars 3.41k forks source link

Refocus after Dialog close triggers Tab change #1121

Open pfeigl opened 5 years ago

pfeigl commented 5 years ago

The DialogHost tries to "re-focus" the item previously selected. This is the code for it: https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit/blob/5533b50a6cff78cb75fbb52e16f7c9e06c62446c/MaterialDesignThemes.Wpf/DialogHost.cs#L268

This is very problematic, when the previous control was a TabItem, because Focus()ing a TabItem actually activates the respective tab.

Here is a very simple reproduction:

The following happens:

I just created the issue as I'm not sure, what the best solution for this. My current feeling tells me to just check for if(!(dialogHost._restoreFocusDialogClose is TabItem), but there might be other elements, where a re-focus is not desired?

I'd be happy to provide a PR after we agree on a solution.

Also - for now, I'd welcome any idea for a good workaround I could place into the application to make it work for now.

pfeigl commented 5 years ago

For the workaround, this is btw. what I'm using right now, which seems to do the job reasonably well ...

        private void RemoveTabItemFocus()
        {
            var window = Window.GetWindow(this);
            var focusedElement = FocusManager.GetFocusedElement(window);
            if (focusedElement is TabItem)
            {
                FocusManager.SetFocusedElement(window, null);
            }
        }

And than, just make sure to call this before the Dialog is opened.

pfeigl commented 5 years ago

I meanwhile ran into multiple other issues connected to the re-focus. Most of them are mostly relevant, when the Dialog is not used with Input elements but used as a kind of Progress Dialog.

An example would be that when Windows are opened, while the Dialog is open, the window is sent into background after Dialog closes, because the MainWindow is focused again.

For now I added this to the DialogOpened event of our progress dialog

sender.GetType().GetField("_restoreFocusDialogClose", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(sender, null);

As you can see, this is something I have to do the bad way, as this property is not available via the public interface of DialogHost. What I'd actually love to be able to do is to disable the Re-focus functionality via a binding property, i.e. something like

<md:DialogHost RestoreFocus="False" />

Again, I'd happily send the PRs for all of this, but I'd like to have some feedback on it before I do the changes :-)