Некорректное поведение модальных форм при переключении между задачами

Есть десктопное приложение с главным и модальным окнами. Модально окно наследует некоторые поведения от цепочки предков. При переключении между приложениями активируется главное окно вместо модального, при чем произвести какие-то действия на нем нельзя (ведь открыто модальное окно). Приходится активировать модальное окно через список окон в 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);

→ Ссылка
Автор решения: kvvk

Пришлось использовать класс-прокладку для обеспечения корректности поведения во всех классах наследниках:

    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);
    }
}

Минусы:

  1. Вмешиваемся в родительские классы
  2. Бага пропадет, если в последующих методах (OnLoad, OnShown) не будет повторения баговой последовательности (т.е. саму багу никто не отменял)
  3. Пропала "мягкость" появления форм, хотя пользователи восприняли это как фичу ускорения появления формы

Что получили:

  1. При использовании дизайнера форм не нужно изменять InitializeComponent
  2. Не нужен глобальный поиск и замена (в некоторых статичных классах - еще и рефакторинг) ShowDialog() на ShowDialog(parentForm)
→ Ссылка