Некорректное поведение модальных форм при переключении между задачами
Есть десктопное приложение с главным и модальным окнами. Модально окно наследует некоторые поведения от цепочки предков. При переключении между приложениями активируется главное окно вместо модального, при чем произвести какие-то действия на нем нельзя (ведь открыто модальное окно). Приходится активировать модальное окно через список окон в Alt+Tab. Баг наблюдается в Win10 (на Win7 переключение между задачами работает стандартно) Воспроизвести поведение можно и без предков, в комментариях описал, что откуда берется:
public class Form1 : Form
{
static int cloneNum = 0;
public Form1()
{
if (cloneNum > 0)
{
// Это простой пример воспроизведения бага при переключении между формами (Alt+Tab или мышкой в панели задач)
// 1. Стоит задача открыть окно модально без отображения в таскбаре
ShowInTaskbar = false;
// 2. В одном из предков используемых форм в конструкторе есть такая строка
Opacity = 0;
// 3. После использования такого предка и установке следующих значений (например, генерируется в InitializeComponent)
// воспроизводится ошибка переключения между окнами
Opacity = 1D;
MinimumSize = new Size (MinimumSize.Width+1, MinimumSize.Height); // новое значение должно отличаться от MinimumSize, иначе магии не будет
}
Text = $"Click for clone ({cloneNum++})";
this.Click += (s, e) => {
// при переключении между задачами при открытом модальном окне и наблюдается баг
(new Form1()).ShowDialog();
};
}
}
Eсть ли идеи как победить баг, не изменяя поведения предков и не редактировать InitializeComponent каждый раз после входа в режим дизайнера формы?
Ответы (2 шт):
Попробуйте передать в качестве аргумента для showDialog, текущую форму. Тогда все окна вызванные таким образом будут поверх этой формы, но только этой формы, не как в случае с topmost.
ShowDialog(this);
Пришлось использовать класс-прокладку для обеспечения корректности поведения во всех классах наследниках:
public class MyForm : Form
{
private double _opacityOnLoad = 1;
private bool _inited = false;
/// <summary>
/// новое свойство "накрывает" собой базовое, не давая ему меняться через InitializeComponent
/// </summary>
public new double Opacity
{
get => _inited ? base.Opacity : _opacityOnLoad;
set { if (_inited) base.Opacity = value; else _opacityOnLoad = value; }
}
protected override void OnLoad(EventArgs e)
{
_inited = true;
// после предварительных установок устанавливаем новое значение.
base.Opacity = _opacityOnLoad;
base.OnLoad(e);
}
}
Минусы:
- Вмешиваемся в родительские классы
- Бага пропадет, если в последующих методах (OnLoad, OnShown) не будет повторения баговой последовательности (т.е. саму багу никто не отменял)
- Пропала "мягкость" появления форм, хотя пользователи восприняли это как фичу ускорения появления формы
Что получили:
- При использовании дизайнера форм не нужно изменять InitializeComponent
- Не нужен глобальный поиск и замена (в некоторых статичных классах - еще и рефакторинг) ShowDialog() на ShowDialog(parentForm)