Показать форму без кражи фокуса?

Я использую форму для показа уведомлений (она отображается в правом нижнем углу экрана), но когда я показываю эту форму, она крадет фокус из основной формы. Есть ли способ показать эту форму "уведомления" без кражи фокуса?

Ответ 1

Hmmm, не просто переопределяет Form.ShowWithoutActivation достаточно?

protected override bool ShowWithoutActivation
{
  get { return true; }
}

И если вы не хотите, чтобы пользователь также щелкнул по этому окну уведомлений, вы можете переопределить CreateParams:

protected override CreateParams CreateParams
{
  get
  {
    CreateParams baseParams = base.CreateParams;

    const int WS_EX_NOACTIVATE = 0x08000000;
    const int WS_EX_TOOLWINDOW = 0x00000080;
    baseParams.ExStyle |= ( int )( WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW );

    return baseParams;
  }
}

Ответ 2

Украден из PInvoke.net ShowWindow метод

private const int SW_SHOWNOACTIVATE = 4;
private const int HWND_TOPMOST = -1;
private const uint SWP_NOACTIVATE = 0x0010;

[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
static extern bool SetWindowPos(
     int hWnd,             // Window handle
     int hWndInsertAfter,  // Placement-order handle
     int X,                // Horizontal position
     int Y,                // Vertical position
     int cx,               // Width
     int cy,               // Height
     uint uFlags);         // Window positioning flags

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

static void ShowInactiveTopmost(Form frm)
{
     ShowWindow(frm.Handle, SW_SHOWNOACTIVATE);
     SetWindowPos(frm.Handle.ToInt32(), HWND_TOPMOST,
     frm.Left, frm.Top, frm.Width, frm.Height,
     SWP_NOACTIVATE);
}

(Алекс Лайман ответил на это, я просто расширяю его, просто вставляя код. Кто-то, у кого есть права редактирования, может его скопировать и удалить для меня все, что мне нужно;))

Ответ 3

Если вы готовы использовать Win32 P/Invoke, вы можете использовать метод ShowWindow (первый пример кода делает именно то, что вы хотите).

Ответ 4

Это то, что сработало для меня. Он обеспечивает TopMost, но без фокуса.

    protected override bool ShowWithoutActivation
    {
       get { return true; }
    }

    private const int WS_EX_TOPMOST = 0x00000008;
    protected override CreateParams CreateParams
    {
       get
       {
          CreateParams createParams = base.CreateParams;
          createParams.ExStyle |= WS_EX_TOPMOST;
          return createParams;
       }
    }

Не забудьте указать параметр TopMost в дизайнере Visual Studio или в другом месте.

Это украдено, ошибочно, заимствовано отсюда (нажмите "Обходные пути" ):

https://connect.microsoft.com/VisualStudio/feedback/details/401311/showwithoutactivation-is-not-supported-with-topmost

Ответ 5

Выполнение этого похоже на хак, но, похоже, он работает:

this.TopMost = true;  // as a result the form gets thrown to the front
this.TopMost = false; // but we don't actually want our form to always be on top

Изменить: обратите внимание, что это просто создает уже созданную форму без кражи фокуса.

Ответ 6

Образец кода из pinvoke.net в ответах Alex Lyman/TheSoftwareJedi сделает окно "самым верхним" окном, что означает, что после его появления вы не сможете поместить его в нормальные окна. Учитывая описание Матиаса того, что он хочет использовать, это может быть то, что он хочет. Но если вы хотите, чтобы пользователь мог поместить ваше окно за другие окна после того, как вы его всплыли, просто используйте HWND_TOP (0) вместо HWND_TOPMOST (-1) в образце.

Ответ 7

В WPF вы можете решить это следующим образом:

В окне поместите эти атрибуты:

<Window
    x:Class="myApplication.winNotification"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="Notification Popup" Width="300" SizeToContent="Height"
  WindowStyle="None" AllowsTransparency="True" Background="Transparent" ShowInTaskbar="False" Topmost="True" Focusable="False" ShowActivated="False" >
</Window>

Последний атрибут - тот, который вам нужен. ShowActivated = "False".

Ответ 8

Возможно, вам захочется рассмотреть, какое уведомление вы хотите отобразить.

Если абсолютно необходимо сообщить пользователю о каком-либо событии, использование Messagebox.Show было бы рекомендуемым способом из-за его природы блокировать любые другие события в главном окне, пока пользователь не подтвердит это. Однако помните о всплывающей слепоте.

Если это меньше критического значения, вы можете использовать альтернативный способ отображения уведомлений, например панель инструментов в нижней части окна. Вы написали, что вы показываете уведомления в правом нижнем углу экрана - стандартный способ сделать это будет использовать подсказку шара с сочетание значка в системном трее.

Ответ 9

Создайте и запустите форму уведомления в отдельном потоке и reset, чтобы вернуться к основной форме после открытия формы. У формы уведомления есть событие OnFormOpened, которое запускается из события Form.Shown. Что-то вроде этого:

private void StartNotfication()
{
  Thread th = new Thread(new ThreadStart(delegate
  {
    NotificationForm frm = new NotificationForm();
    frm.OnFormOpen += NotificationOpened;
    frm.ShowDialog();
  }));
  th.Name = "NotificationForm";
  th.Start();
} 

private void NotificationOpened()
{
   this.Focus(); // Put focus back on the original calling Form
}

Вы также можете сохранить дескриптор объекта NotifcationForm, чтобы он мог программно закрываться основной формой (frm.Close()).

Некоторые детали отсутствуют, но, надеюсь, это поможет вам двигаться в правильном направлении.

Ответ 10

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

this.Focus();

чтобы вернуть фокус в основную форму.

Ответ 11

Это хорошо работает.

См.: OpenIcon - MSDN и SetForegroundWindow - MSDN

using System.Runtime.InteropServices;

[DllImport("user32.dll")]
static extern bool OpenIcon(IntPtr hWnd);

[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);

public static void ActivateInstance()
{
    IntPtr hWnd = IntPtr hWnd = Process.GetCurrentProcess().MainWindowHandle;

    // Restore the program.
    bool result = OpenIcon(hWnd); 
    // Activate the application.
    result = SetForegroundWindow(hWnd);

    // End the current instance of the application.
    //System.Environment.Exit(0);    
}

Ответ 12

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

Во всяком случае, я столкнулся с этим и решил его, используя свойство DateTime, чтобы не допустить дальнейших вызовов BringToFront, если вызовы были сделаны уже недавно.

Предположим, что основной класс "Core", который обрабатывает, например, три формы: "Form1, 2 и 3". Каждая форма нуждается в свойстве DateTime и событии Activate, которое вызывает Core для переноса окон на передний план:

internal static DateTime LastBringToFrontTime { get; set; }

private void Form1_Activated(object sender, EventArgs e)
{
    var eventTime = DateTime.Now;
    if ((eventTime - LastBringToFrontTime).TotalMilliseconds > 500)
        Core.BringAllToFront(this);
    LastBringToFrontTime = eventTime;
}

И затем создайте работу в Core Class:

internal static void BringAllToFront(Form inForm)
{
    Form1.BringToFront();
    Form2.BringToFront();
    Form3.BringToFront();
    inForm.Focus();
}

На боковой ноте, если вы хотите восстановить свернутое окно в исходное состояние (не максимизированное), используйте:

inForm.WindowState = FormWindowState.Normal;

Опять же, я знаю, что это просто исправление в отсутствие BringToFrontWithoutFocus. Это подразумевается как предположение, если вы хотите избежать DLL файла.

Ответ 13

Я не знаю, считается ли это некроположением, но это то, что я сделал с тех пор, как я не смог заставить его работать с методами userWindow и ShowWindow. И нет, переопределение "ShowWithoutActivation" не работает в этом случае, так как новое окно должно быть всегда на вершине. Во всяком случае, я создал вспомогательный метод, который принимает форму как параметр; когда он вызывается, он показывает форму, выводит ее на передний план и делает ее TopMost без кражи фокуса текущего окна (видимо, это так, но пользователь не заметит).

    [DllImport("user32.dll")]
    static extern IntPtr GetForegroundWindow();

    [DllImport("user32.dll")]
    static extern IntPtr SetForegroundWindow(IntPtr hWnd);

    public static void ShowTopmostNoFocus(Form f)
    {
        IntPtr activeWin = GetForegroundWindow();

        f.Show();
        f.BringToFront();
        f.TopMost = true;

        if (activeWin.ToInt32() > 0)
        {
            SetForegroundWindow(activeWin);
        }
    }

Ответ 14

Я знаю, это может показаться глупым, но это сработало:

this.TopMost = true;
this.TopMost = false;
this.TopMost = true;
this.SendToBack();

Ответ 15

Мне нужно было сделать это с моим окном TopMost. Я применил метод PInvoke выше, но обнаружил, что мое событие Load не получило вызова как Talha выше. Я, наконец, добился успеха. Может быть, это поможет кому-то. Вот мое решение:

        form.Visible = false;
        form.TopMost = false;
        ShowWindow(form.Handle, ShowNoActivate);
        SetWindowPos(form.Handle, HWND_TOPMOST,
            form.Left, form.Top, form.Width, form.Height,
            NoActivate);
        form.Visible = true;    //So that Load event happens

Ответ 16

Если это не имеет значения, если первая форма теряет фокус менее 1 секунды, вы можете попробовать это.

private void Form2_Load(object sender, EventArgs e)
{
 Form1 f1 = new Form1();
 f1.focus();
}

Таким образом, когда форма 2 показывает, она будет сразу же сфокусироваться на форме1.

Ответ 17

Я только что нашел очень простое решение: Form.TopMost = true; Form.TopMost = ложь;

Ответ 18

Когда вы создаете новую форму, используя

Form f = new Form();
f.ShowDialog();

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

Исключением является использование threading для создания новой формы, а затем Form.Show(). Убедитесь, что поток глобально виден, потому что, если вы объявите его внутри функции, как только ваша функция выйдет, ваш поток закончится, и форма исчезнет.

Ответ 19

Выяснилось: window.WindowState = WindowState.Minimized;.