Odak çalmadan bir Form gösterilsin mi?


140

Bildirimleri göstermek için bir Form kullanıyorum (ekranın sağ alt kısmında görünür), ancak bu formu gösterdiğimde ana Form'dan odağı çalıyor. Odak çalmadan bu "bildirim" formunu göstermenin bir yolu var mı?

Yanıtlar:


165

Hmmm, Form'u geçersiz kılmıyor, ShowWithoutActivation yeterli mi?

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

Kullanıcının bu bildirim penceresini de tıklamasını istemiyorsanız, CreateParams'ı geçersiz kılabilirsiniz:

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

3
ShowWithoutActivation, Ben bulamadım inanamıyorum, bir öğleden sonra boşa!
deerchao

2
Ayrıca form1.Enabled = falseiç kontrollerin odak çalmasını önlemek için ayarlamam gerekiyor
Jader Dias

23
Ve TopMost'u kapalı bırakın.
mklein

4
TopMost'u istiyorsanız, diğer cevaba bakınız .
Roman Starkov

2
Değerleri WS_EX_NOACTIVATEve WS_EX_TOOLWINDOWvardır 0x08000000ve 0x00000080sırasıyla.
Juan

69

Çalıntı PInvoke.net sitesindeki ShowWindow yöntemi:

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

(Alex Lyman bunu yanıtladı, sadece kodu doğrudan yapıştırarak genişletiyorum. Düzenleme haklarına sahip biri bunu kopyalayabilir ve umursadığım herkes için silebilir;))


Merak ediyordum, gerçekten ekranının sol alt kısmında görüntülenen formun başka bir iş parçacığında olması gerekiyor mu?
Patrick Desjardins

50
Formlarla etkileşim kurmak için hala harici DLL dosyalarına bağlamamız gerektiğini inanılmaz buluyorum. .NET framework sürüm 4'teyiz !! Microsoft'u sarma zamanı.
Maltrap

9
Kabul edilen cevap yanlış. ShowWithoutActivation için arayın
mklein

Sadece frm.Hide () ekleyin ; Formunuzun doğrudan odaklanmasını istemiyorsanız ShowInactiveTopmost işlevinin başında. Unutmayın: System.Runtime.InteropServices kullanarak; kodu çalıştırmak için nasıl
Zitun

1
@Talha Bu kodun Load olayıyla ilgisi yoktur. Load olayı, form gösterilirken değil, form yüklenirken tetiklenir.
TheSoftwareJedi


12

Bu benim için işe yaradı. TopMost sağlar ancak odak çalmaz.

    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 ayarını Visual Studio tasarımcısında veya başka bir yerde atlamayı unutmayın.

Bu buradan çalınmış, err, ödünç alınmıştır (Geçici Çözümlere tıklayın):

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


1
En üstte + odaklanmamış çalışmalar ve tüm cevapların en temizine benziyor.
feos

Microsoft'un sizi kullanırken cezalandırdığı Windows 8'den bu yana en üst düzey kullanımdan kaldırılmıştır. Etkisi, en üstteki bir pencereyi açıp kapattıktan sonra, Windows'un uygulamanızın diğer pencerelerini arka plana taşımasıdır. Bu kesinlikle uygulamanız için istenen davranış değildir. Microsoft bunu uyguladı, çünkü geçmişte birçok programcı en müdahaleci en üst düzeyde istismar etti. En üstte çok agresif. Asla kullanmam.
Elmue

9

Bunu yapmak bir kesmek gibi görünüyor, ancak işe yarıyor gibi görünüyor:

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

Düzenleme: Not, bu sadece odak çalmadan önceden oluşturulmuş bir formu yükseltir.


burada çalışmak gibi görünmüyor ... olabilir çünkü bu "bildirim formu" başka bir iş parçacığında açıldı?
Matías

1
Muhtemelen, bu durumda yöntemi tekrar doğru iş parçacığı olarak çağırmak için bir this.Invoke () çağrısı yapmanız gerekir. Genellikle yanlış iş parçacığından formlarla çalışmak, bir istisna atılmasına neden olur.
Matthew Scharley

Bu işe yarasa da, belirtildiği gibi çirkin bir yöntemdir ve belirli koşullar altında benim için BSOD'ye neden olmuştur, bu yüzden buna dikkat edin.
Raphael Smit

Microsoft'un sizi kullanırken cezalandırdığı Windows 8'den bu yana en üst düzey kullanımdan kaldırılmıştır. Etkisi, en üstteki bir pencereyi açıp kapattıktan sonra, Windows'un uygulamanızın diğer pencerelerini arka plana taşımasıdır. Bu kesinlikle uygulamanız için istenen davranış değildir. Microsoft bunu uyguladı, çünkü geçmişte birçok programcı en müdahaleci en üst düzeyde istismar etti. En üstte çok agresif. Asla kullanmam.
Elmue

9

Alex Lyman / TheSoftwareJedi'nin cevaplarındaki pinvoke.net'ten alınan örnek kod, pencereyi "en üstteki" bir pencere haline getirecektir, bu da açıldıktan sonra normal pencerelerin arkasına koyamayacağınız anlamına gelir. Matias'ın bunu ne için kullanmak istediğine dair açıklaması göz önüne alındığında, istediği bu olabilir. Ancak, kullanıcının pencerenizi açtıktan sonra diğer pencerelerin arkasına koymasını istiyorsanız, örnekte HWND_TOPMOST (-1) yerine HWND_TOP (0) kullanın.


6

WPF'de şu şekilde çözebilirsiniz:

Pencereye şu nitelikleri koyun:

<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>

Son öznitelik ihtiyacınız olan ShowActivated = "False".


4

Benzer bir şeyim var ve sadece bildirim formunu gösterip

this.Focus();

odağı ana forma geri getirmek.


Basit ama etkili!
Tom

3

Bildirim Formunu ayrı bir iş parçacığında oluşturun ve başlatın ve Form açıldıktan sonra odağı ana formunuza sıfırlayın. Bildirim Formundan, Form.Shownolaydan tetiklenen bir OnFormOpened olayı sağlayın . Bunun gibi bir şey:

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
}

Ayrıca, NotifcationForm nesnenizin tutamacını ana Form ( frm.Close()) tarafından program aracılığıyla kapatılabilmesi için tutabilirsiniz .

Bazı ayrıntılar eksik, ancak umarım bu doğru yönde ilerlemenizi sağlar.


Bu, yalnızca formunuz orijinal olarak etkin formsa çalışır. Bu tür bildirimler bu tür bildirimlerin temel amacına aykırıdır.
Alex Lyman

1
Ha? Bildirimin amacı budur - asıl olarak aktif forma geri odaklanmak ve yeniden odaklanmak.
Bob Nadler

2
Bu sadece uygulamanızdaki bir forma odaklanır - ya o sırada başka bir program aktifse? Bir bildirim penceresi göstermek (genellikle kullanıcıya uygulamanızın durumu hakkında güncelleme yapmak için) yalnızca uygulamanızı izlemediğinde yararlı olur.
Alex Lyman

3

Ne tür bir bildirim görüntülemek istediğinizi düşünmek isteyebilirsiniz.

Kullanıcıya Messagebox'ı kullanarak bir olay hakkında bilgi vermek kesinlikle kritikse, ana pencere üzerindeki diğer olayları kullanıcı onaylayana kadar engellemesinin doğası gereği önerilen yol gösterilecektir. Ancak pop-up körlüğünün farkında olun.

Kritik durumdan daha azsa, bildirimleri görüntülemek için pencerenin altındaki araç çubuğu gibi alternatif bir yol kullanmak isteyebilirsiniz. Bildirimleri ekranın sağ alt köşesinde görüntülediğinizi yazdınız - bunu yapmanın standart yolu , bir sistem tepsisi simgesinin kombinasyonuyla bir balon ucu kullanmak olacaktır .


2
Statusbar program recomendations için neyse sayesinde minimize varsa gizli olabilir - - Engelli olabilir çünkü Balon ipuçları bir seçenek değildir
Matías

3

Bu iyi çalışıyor.

Bakınız: OpenIcon - MSDN ve 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);    
}

1

Sen can ben aslında odak çalmak olmadan BringToFront yöntemi ile sona nerede Yukarıdaki öneriler en zarif biri olduğunu itiraf etmeliyim rağmen, tek başına çok mantıkla idare.

Her neyse, ben bu koştu ve son zamanlarda aramalar yapılmışsa daha fazla BringToFront çağrıları izin vermemek için bir DateTime özelliği kullanarak çözdü.

Örneğin, üç formu ('Form1, 2 ve 3') işleyen bir çekirdek sınıf olan 'Core' varsayalım. Her form, pencereleri öne getirmek için Core'u çağıran bir DateTime özelliğine ve bir Activate olayına ihtiyaç duyar:

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

Ve sonra Çekirdek Sınıfta çalışma oluşturun:

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

Yan notta, simge durumuna küçültülmüş bir pencereyi orijinal durumuna (simge durumuna getirilmemiş) geri yüklemek istiyorsanız, şunu kullanın:

inForm.WindowState = FormWindowState.Normal;

Yine, bunun bir BringToFrontWithoutFocus eksikliğinde sadece bir yama çözümü olduğunu biliyorum. DLL dosyasından kaçınmak istiyorsanız bir öneri olarak kastedilmektedir.


1

Bu necro gönderme olarak kabul edilir bilmiyorum, ama bu ı user32's "ShowWindow" ve "SetWindowPos" yöntemleri ile çalışma alamadım beri ne yaptı. Ve hayır, yeni pencerenin her zaman üstte olması gerektiğinden "ShowWithoutActivation" geçersiz kılınmaz. Neyse, parametre olarak bir form alan bir yardımcı yöntem oluşturdum; çağrıldığında, formu gösterir, öne getirir ve geçerli pencerenin odağını çalmadan TopMost yapar (görünüşe göre öyle, ancak kullanıcı fark etmez).

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

0

Kulağa aptalca gelebileceğini biliyorum, ama bu işe yaradı:

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

Ön pencereyi arkaya gönderirseniz, arka plan pencerelerinin yeni ön planın üzerine gelip gelmediği artık görünmeyebilir.
TamusJRoyce

0

Bunu pencerem TopMost ile yapmam gerekiyordu. Yukarıdaki PInvoke yöntemini uyguladım ancak Load etkinimin yukarıdaki Talha gibi çağrılmadığını buldum. Sonunda başardım. Belki bu birisine yardım eder. İşte benim çözümüm:

        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

-4

Kullanarak yeni bir form oluşturduğunuzda

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

bu form kapatılıncaya kadar kodunuz ana formda yürütülmeye devam edemediği için odağı çalar.

Bunun istisnası, yeni bir form oluşturmak için iş parçacığı kullanarak Form.Show () yöntemidir. Bununla birlikte, iş parçacığının genel olarak görünür olduğundan emin olun, çünkü bir işlev içinde bildirirseniz, işlevinizden çıkar çıkmaz iş parçanız sona erer ve form kaybolur.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.