Mam aplikację C # winforms, która uruchamia makro w innym programie. Drugi program będzie ciągle wyskakiwał okienka i ogólnie sprawiał, że rzeczy wyglądały, z braku lepszego słowa, szalone. Chcę zaimplementować przycisk anulowania, który zatrzyma proces, ale nie mogę sprawić, by okno pozostało na wierzchu. Jak to zrobić w C #?
Edycja: próbowałem TopMost = true; , ale drugi program ciągle wyskakuje swoje własne okna. Czy istnieje sposób, aby wysłać moje okno na górę co n milisekund?
Edycja: Sposób, w jaki to rozwiązałem, polegał na dodaniu ikony w zasobniku systemowym, która anuluje proces, klikając ją dwukrotnie. Ikona w zasobniku systemowym nie jest zasłonięta. Dziękuję wszystkim, którzy odpowiedzieli. Przeczytałem artykuł o tym, dlaczego nie ma okna „super na górze” ... logicznie nie działa.
Odpowiedzi:
Form.TopMost
będzie działać, chyba że inny program tworzy najwyższe okna.Nie ma możliwości utworzenia okna, które nie jest zakryte przez nowe najwyższe okna innego procesu. Raymond Chen wyjaśnił dlaczego.
źródło
Form.ActiveForm.TopMost
Szukałem, aby moja aplikacja WinForms była „Zawsze na wierzchu”, ale ustawienie „TopMost” nic dla mnie nie dało. Wiedziałem, że jest to możliwe, ponieważ robi to WinAmp (wraz z wieloma innymi aplikacjami).
Zadzwoniłem do pliku „user32.dll”. Nie miałem żadnych skrupułów, żeby to zrobić i działa świetnie. W każdym razie jest to opcja.
Najpierw zaimportuj następującą przestrzeń nazw:
using System.Runtime.InteropServices;
Dodaj kilka zmiennych do deklaracji klasy:
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); private const UInt32 SWP_NOSIZE = 0x0001; private const UInt32 SWP_NOMOVE = 0x0002; private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
Dodaj prototyp funkcji user32.dll:
[DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
Następnie w swoim kodzie (dodałem wywołanie w Form_Load ()) dodaj wywołanie:
SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
Mam nadzieję, że to pomoże. Odniesienie
źródło
Jeśli przez „wariowanie” masz na myśli, że każde okno wciąż odbiera fokus drugiemu, TopMost nie rozwiąże problemu.
Zamiast tego spróbuj:
To pokaże formę „dziecka” bez kradzieży skupienia. Formularz podrzędny również pozostanie na wierzchu swojego rodzica, nawet jeśli rodzic jest aktywowany lub skoncentrowany. Ten kod działa łatwo tylko wtedy, gdy utworzono wystąpienie formularza podrzędnego z poziomu formularza właściciela. W przeciwnym razie może być konieczne ustawienie właściciela za pomocą interfejsu API.
źródło
CalledForm.Owner
na siebie (CalledForm
) spowodujeSystem.ArgumentException
: „Utworzono cykliczne odwołanie do sterowania. Kontrola nie może być własnością ani być rodzicem dla siebie ”.Ustaw Form.TopMost
źródło
Miałem chwilową 5-minutową przerwę i zapomniałem podać pełny formularz w ten sposób:
myformName.ActiveForm.TopMost = true;
Ale to, czego naprawdę chciałem, to TO!
this.TopMost = true;
źródło
Ustaw właściwość formularza na
.TopMost
true.Prawdopodobnie nie chcesz zostawiać go w ten sposób przez cały czas: ustaw go, gdy rozpocznie się proces zewnętrzny, i odłóż go, gdy się zakończy.
źródło
Sposób, w jaki to rozwiązałem, polegał na utworzeniu ikony w zasobniku systemowym z opcją anulowania.
źródło
Poniższy kod sprawia, że okno zawsze pozostaje na wierzchu, a także sprawia, że jest bezramowe.
using System; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; namespace StayOnTop { public partial class Form1 : Form { private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); private const UInt32 SWP_NOSIZE = 0x0001; private const UInt32 SWP_NOMOVE = 0x0002; private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE; [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); public Form1() { InitializeComponent(); FormBorderStyle = FormBorderStyle.None; TopMost = true; } private void Form1_Load(object sender, EventArgs e) { SetWindowPos(this.Handle, HWND_TOPMOST, 100, 100, 300, 300, TOPMOST_FLAGS); } protected override void WndProc(ref Message m) { const int RESIZE_HANDLE_SIZE = 10; switch (m.Msg) { case 0x0084/*NCHITTEST*/ : base.WndProc(ref m); if ((int)m.Result == 0x01/*HTCLIENT*/) { Point screenPoint = new Point(m.LParam.ToInt32()); Point clientPoint = this.PointToClient(screenPoint); if (clientPoint.Y <= RESIZE_HANDLE_SIZE) { if (clientPoint.X <= RESIZE_HANDLE_SIZE) m.Result = (IntPtr)13/*HTTOPLEFT*/ ; else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE)) m.Result = (IntPtr)12/*HTTOP*/ ; else m.Result = (IntPtr)14/*HTTOPRIGHT*/ ; } else if (clientPoint.Y <= (Size.Height - RESIZE_HANDLE_SIZE)) { if (clientPoint.X <= RESIZE_HANDLE_SIZE) m.Result = (IntPtr)10/*HTLEFT*/ ; else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE)) m.Result = (IntPtr)2/*HTCAPTION*/ ; else m.Result = (IntPtr)11/*HTRIGHT*/ ; } else { if (clientPoint.X <= RESIZE_HANDLE_SIZE) m.Result = (IntPtr)16/*HTBOTTOMLEFT*/ ; else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE)) m.Result = (IntPtr)15/*HTBOTTOM*/ ; else m.Result = (IntPtr)17/*HTBOTTOMRIGHT*/ ; } } return; } base.WndProc(ref m); } protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.Style |= 0x20000; // <--- use 0x20000 return cp; } } } }
źródło
Jaka jest inna aplikacja, którą próbujesz ukryć widoczność? Czy badałeś inne sposoby osiągnięcia zamierzonego efektu? Zrób to, zanim narażasz swoich użytkowników na takie nieuczciwe zachowanie, jakie opisujesz: to, co próbujesz zrobić, brzmi raczej tak, jak niektóre niegrzeczne witryny robią z oknami przeglądarki ...
Przynajmniej staraj się przestrzegać zasady najmniejszej niespodzianki . Użytkownicy oczekują, że będą mogli samodzielnie określić kolejność większości aplikacji. Nie wiesz, co jest dla nich najważniejsze, więc jeśli coś zmienisz, powinieneś skupić się na popychaniu drugiej aplikacji za wszystko, zamiast promować własną.
Jest to oczywiście trudniejsze, ponieważ Windows nie ma szczególnie wyrafinowanego menedżera okien. Sugerują się dwa podejścia:
źródło
Dlaczego nie zrobić z formularza okna dialogowego:
źródło
TopMost = true
wymusiło moją formę na wszystkim, łącznie z chromem, kiedy w rzeczywistości jest to tylko pudełko ustawień i potrzebowałem go na górze głównej formy. Wyrazy uznania dla osoby internetowej.Oto odpowiednik SetForegroundWindow:
Widziałem ludzi robiących dziwne rzeczy, takie jak:
this.TopMost = true; this.Focus(); this.BringToFront(); this.TopMost = false;
http://blog.jorgearimany.com/2010/10/win32-setforegroundwindow-equivalent-in.html
źródło
this.Show(); this.Activate(); this.BringToFront();
ale ta odpowiedź doprowadziła nas do rozwiązania. Dzięki!Wiem, że to jest stare, ale nie widziałem tej odpowiedzi.
W oknie (xaml) dodaj:
Deactivated="Window_Deactivated"
W kodzie dla Window_Deactivated:
private void Window_Deactivated(object sender, EventArgs e) { Window window = (Window)sender; window.Activate(); }
Dzięki temu okno będzie na górze.
źródło
Opierając się na odpowiedzi clamum i komentarzu Kevina Vuilleumiera na temat drugiej flagi odpowiedzialnej za zachowanie, dokonałem tego przełącznika, który przełącza się między na górze a nie na górze za pomocą naciśnięcia przycisku.
private void button1_Click(object sender, EventArgs e) { if (on) { button1.Text = "yes on top"; IntPtr HwndTopmost = new IntPtr(-1); SetWindowPos(this.Handle, HwndTopmost, 0, 0, 0, 0, TopmostFlags); on = false; } else { button1.Text = "not on top"; IntPtr HwndTopmost = new IntPtr(-2); SetWindowPos(this.Handle, HwndTopmost, 0, 0, 0, 0, TopmostFlags); on = true; } }
źródło