Окно уведомлений - предотвращение получения фокуса окном

У меня некоторые проблемы с корректным поведением окна уведомления на c#. В основном я показываю форму без бордюра в правой нижней части экрана, которая отображает сообщение в течение нескольких секунд, а затем исчезает. Проблема в том, что мне нужно, чтобы она появлялась поверх других окон без возможности перехватить фокус. В идеале я хочу, чтобы это был чисто управляемый код, хотя, просматривая похожие примеры, я сомневаюсь, что это возможно.

На данный момент я предотвращаю кражу фокуса, вызывая Form.Show() с переопределением:

protected override bool ShowWithoutActivation // stops the window from stealing focus
{
    get { return true; }
}

и игнорируя щелчки мыши с помощью:

    private const int WM_MOUSEACTIVATE = 0x0021;
    private const int MA_NOACTIVATEANDEAT = 0x0004;

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_MOUSEACTIVATE)
        {
            m.Result = (IntPtr)MA_NOACTIVATEANDEAT;
            return;
        }
        base.WndProc(ref m);
    }

Однако я обнаружил, что если я использую это в сочетании с TopMost = true (что мне и нужно), он все равно получает фокус, и если все другие окна свернуты, он также получает фокус.

Итак, есть ли способ полностью предотвратить получение формой фокуса (будь то щелчок мыши, alt-tab и т.д.), оставаясь при этом самой верхней/второй по высоте формой? Даже просто вернуть фокус обратно в окно, из которого он был украден, это сработает (хотя и вызовет мерцание).

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

EDIT:

Итак, мне наконец удалось заставить его работать, используя:

protected override bool ShowWithoutActivation // stops the window from stealing focus
{
    get { return true; }
}

// and

const int WS_EX_NOACTIVATE = 0x08000000;
const int WS_EX_TOPMOST = 0x00000008;

protected override CreateParams CreateParams
{
    get
    {
        CreateParams param = base.CreateParams;
        param.ExStyle |= WS_EX_TOPMOST; // make the form topmost
        param.ExStyle |= WS_EX_NOACTIVATE; // prevent the form from being activated
        return param;
    }
}

// and

[DllImport("user32.dll")]
private extern static IntPtr SetActiveWindow(IntPtr handle);
private const int WM_ACTIVATE = 6;
private const int WA_INACTIVE = 0;

private const int WM_MOUSEACTIVATE = 0x0021;
private const int MA_NOACTIVATEANDEAT = 0x0004;

protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_MOUSEACTIVATE)
    {
        m.Result = (IntPtr)MA_NOACTIVATEANDEAT; // prevent the form from being clicked and gaining focus
        return;
    }
    if (m.Msg == WM_ACTIVATE) // if a message gets through to activate the form somehow
    {
        if (((int)m.WParam & 0xFFFF) != WA_INACTIVE)
        {

            if (m.LParam != IntPtr.Zero)
            {
                SetActiveWindow(m.LParam);
            }
            else
            {
                // Could not find sender, just in-activate it.
                SetActiveWindow(IntPtr.Zero);
            }

        }
    }

Я также добавил Form.Hide() к событию GotFocus, так что даже если он каким-то образом получит фокус, он просто закроется и уберется с пути пользователя как можно скорее.

Также, если кому-то интересно, константы для всех стилей окна и т.д. можно найти в WINUSER.H, он находится онлайн по адресу http://www.woodmann.com/fravia/sources/WINUSER.H, если вы не можете его найти.

Однако, если кто-то видит более элегантный способ сделать это, он будет благодарен.

6
задан casperOne 27 July 2012 в 15:06
поделиться