Подтвердить что ты не робот

Приложение WPF полностью теряет фокус на закрытии окна

Описание проблемы

Если я создаю немодальное окно в качестве дочернего окна, установив Владелец окна в родительское окно, а затем покажу MessageBox из этого дочернего окна, родительское окно потеряет фокус, если я закрою дочернее окно, Если Windows Explorer или другое приложение открыто, это приложение получит фокус, и основное окно будет скрыто.

Это, похоже, известная проблема, поскольку я видел ее в другой группах новостей, но я не видел хорошего решения. Установка владельца в null в OnDeactivate не является опцией. Установка владельца, прежде чем показывать MessageBox в null и сбросить его после этого, не поможет. Установка владельца в null в событии OnClosed также не помогает.

найдено простое решение

Если у вас возникла такая же проблема, как я описал, поставьте следующий код в OnClosing всех дочерних окон.

void  OnClosing(System.ComponentModel.CancelEventArgs e)
  base.OnClosing(e);
  if (null != Owner) {
         Owner.Activate();
  }
  // ....

За ним может следовать любая дальнейшая логика обработки, допускается даже открытие MessageBoxes.

Пример-код

Вопрос, кажется, намного больше, как я думал. Следующий пример удалит фокус родительского окна, если окно сообщения будет открыто и дочернее окно будет закрыто (скопируйте код в загруженный обработчик событий окна).

Window firstChildWindow = new Window() {
    Title = "Floating Window", Width = 100, Height = 70
};
firstChildWindow.Owner = Window.GetWindow(this);

Button button = new Button() { Content="MessageBox"};
button.Click += delegate { 
    MessageBox.Show("Klicking her breaks the focus-chain."); };
firstChildWindow.Content = button;
firstChildWindow.Show();

Также этот пример разбивает цепочку фокуса:

Window firstChildWindow = new Window() {
    Title = "Floating Window", Width = 100, Height = 70
};
firstChildWindow.Owner = Window.GetWindow(this);
firstChildWindow.Show();

Window secondChildWindow = new Window() { 
    Title="Second Window",Width=100,Height=70};
secondChildWindow.Content = new TextBlock() { 
    Text="SecondWindow"};
secondChildWindow.Owner = firstChildWindow;
secondChildWindow.Show();

У кого-то есть разрешение на эту проблему. Я думаю о взломе, чтобы вызвать фокус на родителя после закрытия, с Dispatcher или DispachterTimer, или, возможно, это будет работать с ручной фокусировкой на родителя на закрытом, но все это кажется мне очень нечистым (и также немного сложно, если есть более активные окна одного и того же родителя, как в моем текущем приложении).

Никто не знает, насколько это возможно?

Ресурсы

Описание MSDN (см. примечания для не модальных окон, открытых вызовом Show())

Такая же проблема на форумах msdn без соответствующего решения

См. также: Нестабильный фокус приложений WPF

4b9b3361

Ответ 1

Что наиболее вероятно произошло здесь, у вас есть два независимых окна верхнего уровня и один из них закрыт. Это иногда приводит к тому, что фокус переходит в другое приложение.

Это также происходит, если одному окну принадлежит вторая, которая, в свою очередь, владеет третьим. Вероятная ошибка в Win32 API, но она была с нами навсегда, так что удача в том, что она исправлена.

Обходной путь заключается в том, чтобы вручную вернуть фокус обратно ребенку в событие закрытия внука. Но в этом случае внук является почтовым ящиком, поэтому вы не можете этого сделать. Самое простое - создать собственный почтовый ящик для родителя. Следующим проще всего сделать свой собственный контроль над сообщениями.

Ответ 2

Это очень раздражающая ошибка, наиболее распространенное решение:

вызов Me.Owner.Focus в событии Window_Unloaded или Window_Closing.

Но это все еще не работает на 100%, вы все равно видите, что фоновое окно мигает на передний план (очень кратко), прежде чем фокус будет восстановлен правильно.

Я нашел метод, который работает лучше:

вызов Me.Owner.Activate до Me.Close (или в событии _Closing).

Ответ 3

Возможно, я довольно поздно по этому поводу.
@HCL эту проблему можно было бы решить легче, установив параметр options MessageBox.show() на MessageBoxOptions.None.

Приветствие...

Ответ 4

можно написать свой собственный почтовый ящик, вы можете реализовать его как floater, отключив весь экран, когда будет показано.

вы проверяете образец caliburn mvvm frameork, есть хорошая реализация Messagebox в качестве сервиса.

Ответ 5

Собственность не имеет никакого отношения к активации окна. Чтобы увидеть это, измените владельца второго окна на верхнее окно и запустите программу. Обратите внимание, что ничего не меняется. Собственность связана с "Если окно сведено к минимуму, какие другие окна нужно минимизировать". Таким образом, вы застряли в использовании пользовательского кода активации.

Ответ 6

Johsua.Activate(см. выше) решение работает довольно хорошо со всеми типами окон. По крайней мере, это помогло мне.

Ответ 7

У меня была аналогичная проблема. У меня было одно главное окно, где дочерние дочерние окна были привязаны к этому окну через свойство Owner. Если в главном окне было два или более детей, после закрытия второго ребенка приложение потеряло фокус. Я использовал трюк с child.Owner = null до закрытия, но затем мое следующее дочернее окно теряет фокус. Я справился с этим, забрав всех детей и сосредоточившись на последнем, прежде чем закрыть ребенка. Вот пример кода:

private void OnClosing(object sender, CancelEventArgs cancelEventArgs)
        {
            var childWindows = (sender as Window).Owner.OwnedWindows;
            if (childWindows.Count - 2 >= 0)
                childWindows[childWindows.Count - 2].Focus();
            else
            {
                (sender as Window).Owner.Focus();
            }
            (sender as Window).Owner = null;
        }