Przenieś okno do przodu w WPF

214

Jak mogę przenieść moją aplikację WPF na przód pulpitu? Do tej pory próbowałem:

SwitchToThisWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle, true);

SetWindowPos(new WindowInteropHelper(Application.Current.MainWindow).Handle, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

SetForegroundWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle);

Żadne z nich nie wykonuje zadania ( Marshal.GetLastWin32Error()mówi, że te operacje zostały zakończone pomyślnie, a atrybuty P / Invoke dla każdej definicji mają SetLastError=true).

Jeśli utworzę nową pustą aplikację WPF i zadzwonię SwitchToThisWindowz zegarem, działa ona dokładnie tak, jak się spodziewano, więc nie jestem pewien, dlaczego nie działa w moim oryginalnym przypadku.

Edycja : Robię to w połączeniu z globalnym skrótem klawiszowym.

Factor Mystic
źródło
Czy sprawdziłeś, że MainWindow to okno, które chcesz? Z MSDN: MainWindow jest automatycznie ustawiany w odniesieniu do pierwszego obiektu Window, który ma zostać utworzony w AppDomain.
Todd White
Dobra myśl, ale jest to jedyne okno w aplikacji.
Factor Mystic
Czy możesz podać nieco więcej kodu kontekstowego?
Todd White

Odpowiedzi:

314
myWindow.Activate();

Próbuje przenieść okno na pierwszy plan i aktywuje je.

To powinno wystarczyć, chyba że źle zrozumiałem, a ty chcesz zachowania Always on Top. W takim przypadku chcesz:

myWindow.TopMost = true;
Morten Christiansen
źródło
14
Po prostu korzystałem z myWindow.Show () i czasami nie było na topie. Zaraz potem zadzwoniłem do myWindow.Activate () i zadziałało.
Bermo
4
Aktywacja czasami nie działa w systemie Windows XP. Polecam odpowiedź @Matthew Xaviera.
Lex Li
Trochę dziwne, ponieważ domyślnie ShowActivated jest włączony.
greenoldman
1
Pierwsza odpowiedź jest dobra, dziękuję za to! Ale drugi wiersz kodu, korzystanie z tej Topmostwłaściwości, jest złą praktyką, ponieważ może zasłaniać inne wyskakujące okna dialogowe i mieć nieoczekiwane zachowanie.
Jonathan Perry
2
W rzeczywistości można to zrobić w ten sposób: if (myWindow.WindowState == WindowState.Minimized) myWindow.WindowState = WindowState.Normal;Dziwnie, zachowa również wszystkie zmaksymalizowane okna i nie przywróci ich do stanu normalnego.
r41n
168

Znalazłem rozwiązanie, które przenosi okno na górę, ale zachowuje się jak normalne okno:

if (!Window.IsVisible)
{
    Window.Show();
}

if (Window.WindowState == WindowState.Minimized)
{
    Window.WindowState = WindowState.Normal;
}

Window.Activate();
Window.Topmost = true;  // important
Window.Topmost = false; // important
Window.Focus();         // important
Jader Dias
źródło
1
Świetna wskazówka! TopMost sprawia, że ​​magia dzieje się w systemie Windows 7, jeśli okno jest już otwarte, ale pod innymi oknami.
gsb
To też załatwiło sprawę dla mnie. Dzięki gsb za dodatkowy komentarz na temat dziwnego użycia TopMost!
Jen
1
Dzięki - poprawka była krótka i słodka.
code4life
2
W moim przypadku wystarczyły Window.Activate () i Window.Focus (). Ustawienie Window.TopMost jest niepotrzebne.
wirusowy
6
Nie używać Window.Focus(). Spowoduje to oderwanie się od tego, co użytkownik wpisuje w polu tekstowym, co jest niezwykle frustrujące dla użytkowników końcowych. Powyższy kod działa bez niego dobrze.
Contango,
32

Jeśli chcesz, aby okno znajdowało się z przodu przy pierwszym ładowaniu, wykonaj następujące czynności:

private void Window_ContentRendered(object sender, EventArgs e)
{
    this.Topmost = false;
}

private void Window_Initialized(object sender, EventArgs e)
{
    this.Topmost = true;
}
Amir
źródło
1
Jeśli rozwiniesz coś podobnego do Launchy ( launchy.net ) w C #, powinieneś zauważyć, że ta odpowiedź jest prawie bezużyteczna.
Lex Li
21

Aby było to szybkie kopiowanie-wklejanie -
użyj tej DoOnProcessmetody „ metody, aby przenieść okno główne procesu” na pierwszy plan (ale nie kradnij fokusu z innych okien)

public class MoveToForeground
{
    [DllImportAttribute("User32.dll")]
    private static extern int FindWindow(String ClassName, String WindowName);

    const int SWP_NOMOVE        = 0x0002;
    const int SWP_NOSIZE        = 0x0001;            
    const int SWP_SHOWWINDOW    = 0x0040;
    const int SWP_NOACTIVATE    = 0x0010;
    [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);

    public static void DoOnProcess(string processName)
    {
        var allProcs = Process.GetProcessesByName(processName);
        if (allProcs.Length > 0)
        {
            Process proc = allProcs[0];
            int hWnd = FindWindow(null, proc.MainWindowTitle.ToString());
            // Change behavior by settings the wFlags params. See http://msdn.microsoft.com/en-us/library/ms633545(VS.85).aspx
            SetWindowPos(new IntPtr(hWnd), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
        }
    }
}

HTH

Hertzel Guinness
źródło
6
+1 to jedyna odpowiedź, która była dla mnie przydatna. Mam aplikację z jednym urządzeniem głównym i kilkoma pływającymi oknami podrzędnymi. Po aktywacji któregokolwiek z nich, wszystkie pozostałe okna również powinny zostać przesunięte na przód. Ale nie aktywowano / nie skupiono się, jak sugeruje większość odpowiedzi: jest to katastrofa, ponieważ powoduje, że okno aktualnie klikane jest nie do kliknięcia, ponieważ nagle inne okno staje się aktywne.
stijn
Czy jest jakiś powód do nieużywania process.MainWindowHandle?
Sriram Sakthivel
W moim przypadku nie chciałem głównego okna, ale zgodziłem się, że są inne sposoby na uzyskanie hWnd. FWIW HwndSourceobiekt działał dobrze.
tobriand
21

Wiem, że to pytanie jest dość stare, ale właśnie natknąłem się na ten precyzyjny scenariusz i chciałem podzielić się wdrożonym przeze mnie rozwiązaniem.

Jak wspomniano w komentarzach na tej stronie, kilka proponowanych rozwiązań nie działa na XP, które muszę wspierać w moim scenariuszu. Chociaż zgadzam się z opinią @Matthew Xaviera, że ​​ogólnie jest to zła praktyka UX, są chwile, w których jest to całkowicie prawdopodobne UX.

Rozwiązanie przeniesienia okna WPF na samą górę zostało mi zapewnione przez ten sam kod, którego używam do zapewnienia globalnego skrótu. Artykuł na blogu Josepha Cooneya zawiera link do jego próbek kodu, który zawiera oryginalny kod.

Wyczyściłem i zmodyfikowałem trochę kod i zaimplementowałem go jako metodę rozszerzenia do System.Windows.Window. Przetestowałem to na XP 32-bitowym i Win7 64-bitowym, oba działają poprawnie.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Interop;
using System.Runtime.InteropServices;

namespace System.Windows
{
    public static class SystemWindows
    {
        #region Constants

        const UInt32 SWP_NOSIZE = 0x0001;
        const UInt32 SWP_NOMOVE = 0x0002;
        const UInt32 SWP_SHOWWINDOW = 0x0040;

        #endregion

        /// <summary>
        /// Activate a window from anywhere by attaching to the foreground window
        /// </summary>
        public static void GlobalActivate(this Window w)
        {
            //Get the process ID for this window's thread
            var interopHelper = new WindowInteropHelper(w);
            var thisWindowThreadId = GetWindowThreadProcessId(interopHelper.Handle, IntPtr.Zero);

            //Get the process ID for the foreground window's thread
            var currentForegroundWindow = GetForegroundWindow();
            var currentForegroundWindowThreadId = GetWindowThreadProcessId(currentForegroundWindow, IntPtr.Zero);

            //Attach this window's thread to the current window's thread
            AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, true);

            //Set the window position
            SetWindowPos(interopHelper.Handle, new IntPtr(0), 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);

            //Detach this window's thread from the current window's thread
            AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, false);

            //Show and activate the window
            if (w.WindowState == WindowState.Minimized) w.WindowState = WindowState.Normal;
            w.Show();
            w.Activate();
        }

        #region Imports

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

        [DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

        [DllImport("user32.dll")]
        private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);

        [DllImport("user32.dll")]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        #endregion
    }
}

Mam nadzieję, że ten kod pomoże innym, którzy napotkają ten problem.

Zodman
źródło
Hej, tam! Walczyłem z tym od miesięcy! Działa to w obu moich sytuacjach. Niesamowite! (Windows 7 x64)
mdiehl13,
Właściwie wydaje się, że działa tylko wtedy, gdy to zrobię: App.mainWindow.Show (); SystemWindows.GlobalActivate (App.mainwindow); // Kiedy
usuwam
+1 dla SetWindowPos (), szukałem sposobu, aby moje okno było na pierwszym planie, bez zakłócania działania innych aplikacji lub kradzieży. this.Activate () kradnie fokus.
ładnie unikaj
Zrobiło to dla mnie i moim celem było kradzież skupienia, tak jak to się dzieje, gdy użytkownik wchodzi w interakcję z pewnym elementem. więc dziękuję bardzo to wydaje się działać spójnie! tylko dzwonienie this.Activate()wydaje się działać czasami.
Peter
13

Jeśli użytkownik wchodzi w interakcję z inną aplikacją, przeniesienie Twojej aplikacji na pierwszy plan może być niemożliwe. Zasadniczo proces może oczekiwać ustawienia okna pierwszego planu, tylko jeśli proces ten jest już procesem pierwszego planu. (Microsoft dokumentuje ograniczenia we wpisie MSDN SetForegroundWindow ()) . Jest tak, ponieważ:

  1. Użytkownik „jest właścicielem” pierwszego planu. Na przykład byłoby bardzo irytujące, gdyby inny program ukradł pierwszy plan podczas pisania przez użytkownika, przynajmniej przerywając jej przepływ pracy i prawdopodobnie powodując niezamierzone konsekwencje, ponieważ jej naciśnięcia klawiszy dla jednej aplikacji są źle interpretowane przez sprawcę, dopóki nie zauważy zmiany .
  2. Wyobraź sobie, że każdy z dwóch programów sprawdza, czy jego okno jest na pierwszym planie i próbuje ustawić go na pierwszym planie, jeśli tak nie jest. Zaraz po uruchomieniu drugiego programu komputer staje się bezużyteczny, gdy pierwszy plan odbija się między nimi przy każdym przełączeniu zadania.
Matthew Xavier
źródło
Słuszna uwaga. Kod miał jednak związek z globalnym skrótem klawiszowym, a inne aplikacje robią to w jakiś sposób.
Factor Mystic
Muszę użyć PInvoke w C # do emulacji tego, co opisano w tym artykule, codeproject.com/Tips/76427/…
Lex Li
dlaczego więc okna dialogowe wyskakujących okienek błędów mieszania pozostają widoczne, gdy czasami przełączam się na Visual Studio? : - /
Simon_Weaver
Simon, podejrzewam, że wyskakujące okienka błędów są „najwyższymi” oknami (decyzja projektowa, którą odrzucam). Istnieje różnica między oknem pierwszego planu (który otrzymuje dane wejściowe od użytkownika) a oknem „znajdującym się najwyżej” w kolejności Z. Każde okno może stać się „najwyżej”, co umieszcza je na wszystkich oknach, które nie są najwyższe, ale nie daje skupienia na klawiaturze okna itp., Jak robi to okno na pierwszym planie.
Matthew Xavier
Trik kończy się niepowodzeniem w przypadku kilku specjalnych okien. Visual Studio i okna wiersza poleceń muszą mieć coś, co uniemożliwia, że ​​inne okno stanie się oknem pierwszego planu.
Lex Li
9

Wiem, że to późna odpowiedź, być może pomocna dla badaczy

 if (!WindowName.IsVisible)
 {
     WindowName.Show();
     WindowName.Activate();
 }
Jamaxack
źródło
9

Dlaczego niektóre odpowiedzi na tej stronie są błędne!

  • Każda zastosowana odpowiedź window.Focus()jest nieprawidłowa.

    • Czemu? Jeśli pojawi się powiadomienie, window.Focus()odciągnie uwagę od tego, co użytkownik wpisuje w danym momencie. Jest to niezwykle frustrujące dla użytkowników końcowych, szczególnie jeśli wyskakujące okienka pojawiają się dość często.
  • Każda zastosowana odpowiedź window.Activate()jest nieprawidłowa.

    • Czemu? Sprawi, że wszystkie okna nadrzędne będą widoczne.
  • Każda odpowiedź, która window.ShowActivated = falsezostanie pominięta, jest błędna.
    • Czemu? Gdy pojawi się komunikat, przyciągnie uwagę z innego okna, co jest bardzo denerwujące!
  • Każda odpowiedź, która nie służy Visibility.Visibledo ukrywania / pokazywania okna, jest niepoprawna.
    • Czemu? Jeśli używamy Citrix, jeśli okno nie zwinie się po zamknięciu, pozostawi dziwny czarny prostokątny uchwyt na ekranie. Dlatego nie możemy używać window.Show()i window.Hide().

Głównie:

  • Okno nie powinno przyciągać fokusa od żadnego innego okna, gdy zostanie aktywowane;
  • Okno nie powinno aktywować swojego rodzica, gdy jest wyświetlane;
  • Okno powinno być kompatybilne z Citrix.

Rozwiązanie MVVM

Ten kod jest w 100% zgodny z Citrix (bez pustych obszarów ekranu). Jest testowany zarówno z normalnym WPF, jak i DevExpress.

Ta odpowiedź jest przeznaczona dla każdego przypadku użycia, w którym chcemy małe okno powiadomienia, które zawsze znajduje się przed innymi oknami (jeśli użytkownik wybierze to w preferencjach).

Jeśli ta odpowiedź wydaje się bardziej złożona niż inne, to dlatego, że jest to solidny kod na poziomie przedsiębiorstwa. Niektóre inne odpowiedzi na tej stronie są proste, ale w rzeczywistości nie działają.

XAML - właściwość dołączona

Dodaj tę dołączoną właściwość do dowolnej UserControlw oknie. Załączona nieruchomość:

  • Poczekaj, aż Loadedzdarzenie zostanie uruchomione (w przeciwnym razie nie będzie mógł przeglądać drzewa wizualnego w celu znalezienia okna nadrzędnego).
  • Dodaj moduł obsługi zdarzeń, który zapewnia, że ​​okno jest widoczne, czy nie.

W dowolnym momencie możesz ustawić okno tak, aby było na wierzchu lub nie, odwracając wartość dołączonej właściwości.

<UserControl x:Class="..."
         ...
         attachedProperties:EnsureWindowInForeground.EnsureWindowInForeground=
             "{Binding EnsureWindowInForeground, Mode=OneWay}">

C # - Metoda pomocnicza

public static class HideAndShowWindowHelper
{
    /// <summary>
    ///     Intent: Ensure that small notification window is on top of other windows.
    /// </summary>
    /// <param name="window"></param>
    public static void ShiftWindowIntoForeground(Window window)
    {
        try
        {
            // Prevent the window from grabbing focus away from other windows the first time is created.
            window.ShowActivated = false;

            // Do not use .Show() and .Hide() - not compatible with Citrix!
            if (window.Visibility != Visibility.Visible)
            {
                window.Visibility = Visibility.Visible;
            }

            // We can't allow the window to be maximized, as there is no de-maximize button!
            if (window.WindowState == WindowState.Maximized)
            {
                window.WindowState = WindowState.Normal;
            }

            window.Topmost = true;
        }
        catch (Exception)
        {
            // Gulp. Avoids "Cannot set visibility while window is closing".
        }
    }

    /// <summary>
    ///     Intent: Ensure that small notification window can be hidden by other windows.
    /// </summary>
    /// <param name="window"></param>
    public static void ShiftWindowIntoBackground(Window window)
    {
        try
        {
            // Prevent the window from grabbing focus away from other windows the first time is created.
            window.ShowActivated = false;

            // Do not use .Show() and .Hide() - not compatible with Citrix!
            if (window.Visibility != Visibility.Collapsed)
            {
                window.Visibility = Visibility.Collapsed;
            }

            // We can't allow the window to be maximized, as there is no de-maximize button!
            if (window.WindowState == WindowState.Maximized)
            {
                window.WindowState = WindowState.Normal;
            }

            window.Topmost = false;
        }
        catch (Exception)
        {
            // Gulp. Avoids "Cannot set visibility while window is closing".
        }
    }
}

Stosowanie

Aby tego użyć, musisz utworzyć okno w swoim ViewModel:

private ToastView _toastViewWindow;
private void ShowWindow()
{
    if (_toastViewWindow == null)
    {
        _toastViewWindow = new ToastView();
        _dialogService.Show<ToastView>(this, this, _toastViewWindow, true);
    }
    ShiftWindowOntoScreenHelper.ShiftWindowOntoScreen(_toastViewWindow);
    HideAndShowWindowHelper.ShiftWindowIntoForeground(_toastViewWindow);
}

private void HideWindow()
{
    if (_toastViewWindow != null)
    {
        HideAndShowWindowHelper.ShiftWindowIntoBackground(_toastViewWindow);
    }
}

Dodatkowe linki

Aby dowiedzieć się, jak upewnić się, że okno powiadomień zawsze przesuwa się z powrotem na widoczny ekran, zobacz moją odpowiedź: W WPF, jak przenieść okno na ekran, jeśli jest poza ekranem? .

Contango
źródło
5
„Kod na poziomie przedsiębiorstwa” i kilka wierszy później catch (Exception) { }. Tak, prawda ... I używa kodu, który nie jest nawet wyświetlany w odpowiedzi, takiej jak _dialogServicelub ShiftWindowOntoScreenHelper. Plus prośba o utworzenie okna po stronie viewmodel (co w zasadzie psuje cały wzór MVVM) ...
Kryptos
@Kryptos To jest kod na poziomie przedsiębiorstwa. Napisałem to z pamięci, a ta dokładna technika jest stosowana w dużej firmie FTSE100. Rzeczywiste życie jest nieco mniej nieskazitelne w porównaniu z idealnymi wzorami projektowymi, do których wszyscy dążymy.
Contango,
Nie podoba mi się to, że sam trzymamy wystąpienie okna w modelu widoku, jak wspomniał Kryptos, który łamie cały punkt mvvm, może zamiast tego można to zrobić w codebehind?
Igor Meszaros
1
@Igor Meszaros Zgoda. Teraz, gdy mam więcej doświadczenia, gdybym musiał to zrobić ponownie, dodałbym Zachowanie i kontrolowałem je za pomocą Func<>powiązanego z ViewModel.
Contango,
7

Miałem podobny problem z aplikacją WPF, która jest wywoływana z aplikacji Access za pośrednictwem obiektu Shell.

Moje rozwiązanie jest poniżej - działa w XP i Win7 x64 z aplikacją skompilowaną do celu x86.

Wolałbym to zrobić niż symulować klawisz Alt.

void Window_Loaded(object sender, RoutedEventArgs e)
{
    // make sure the window is normal or maximised
    // this was the core of the problem for me;
    // even though the default was "Normal", starting it via shell minimised it
    this.WindowState = WindowState.Normal;

    // only required for some scenarios
    this.Activate();
}
Seth
źródło
4

Cóż, ponieważ jest to tak gorący temat ... oto, co działa dla mnie. Wystąpiły błędy, jeśli nie zrobiłem tego w ten sposób, ponieważ Activate () spowoduje błąd, jeśli nie widzisz okna.

Xaml:

<Window .... 
        Topmost="True" 
        .... 
        ContentRendered="mainWindow_ContentRendered"> .... </Window>

Codebehind:

private void mainWindow_ContentRendered(object sender, EventArgs e)
{
    this.Topmost = false;
    this.Activate();
    _UsernameTextBox.Focus();
}

To był dla mnie jedyny sposób na wyświetlenie okna na górze. Następnie aktywuj go, aby móc pisać w polu bez konieczności ustawiania ostrości za pomocą myszy. control.Focus () nie będzie działać, chyba że okno jest aktywne ();

Omzig
źródło
2

Cóż, wymyśliłem obejście. Dzwonię z haka na klawiaturę używanego do wprowadzenia skrótu. Wywołanie działa zgodnie z oczekiwaniami, jeśli wstawię go do BackgroundWorker z pauzą. To kludge, ale nie mam pojęcia, dlaczego pierwotnie nie działało.

void hotkey_execute()
{
    IntPtr handle = new WindowInteropHelper(Application.Current.MainWindow).Handle;
    BackgroundWorker bg = new BackgroundWorker();
    bg.DoWork += new DoWorkEventHandler(delegate
        {
            Thread.Sleep(10);
            SwitchToThisWindow(handle, true);
        });
    bg.RunWorkerAsync();
}
Factor Mystic
źródło
Po prostu zainteresowany: czy wypróbowałeś Window.Activate (zgodnie z sugestią Mortena) i inne sugestie? Wydają się mniej zuchwałe niż ta przyznana kludge.
Simon D.
To było dość dawno temu, ale tak, w tym czasie próbowałem
Factor Mystic
To nie działa w moim systemie Windows XP. Polecam odpowiedź @Matthew Xaviera.
Lex Li
2

Aby wyświetlić JAKIEKOLWIEK otwarte okno, zaimportuj te biblioteki DLL:

public partial class Form1 : Form
{
    [DllImportAttribute("User32.dll")]
    private static extern int FindWindow(String ClassName, String WindowName);
    [DllImportAttribute("User32.dll")]
    private static extern int SetForegroundWindow(int hWnd);

oraz w programie Szukamy aplikacji o określonym tytule (wpisz tytuł bez pierwszej litery (indeks> 0))

  foreach (Process proc in Process.GetProcesses())
                {
                    tx = proc.MainWindowTitle.ToString();
                    if (tx.IndexOf("Title of Your app WITHOUT FIRST LETTER") > 0)
                    {
                        tx = proc.MainWindowTitle;
                        hWnd = proc.Handle.ToInt32(); break;
                    }
                }
                hWnd = FindWindow(null, tx);
                if (hWnd > 0)
                {
                    SetForegroundWindow(hWnd);
                }
Rahmud
źródło
„Tytuł Twojej aplikacji BEZ PIERWSZEGO LISTU” O , hacky hacky hacky. Dlaczego IndexOfzamiast tego nie używać poprawnie?
Wyścigi lekkości na orbicie
1

Problemem może być to, że wątek wywołujący twój kod z haka nie został zainicjowany przez środowisko wykonawcze, więc wywołanie metod środowiska wykonawczego nie działa.

Być może możesz spróbować wykonać Invoke, aby wprowadzić kod do wątku interfejsu użytkownika i wywołać kod, który przenosi okno na pierwszy plan.

joshperry
źródło
1

Kody te będą działać poprawnie przez cały czas.

Najpierw ustaw aktywowaną procedurę obsługi zdarzeń w XAML:

Activated="Window_Activated"

Dodaj poniższy wiersz do bloku konstruktora okna głównego:

public MainWindow()
{
    InitializeComponent();
    this.LocationChanged += (sender, e) => this.Window_Activated(sender, e);
}

A w aktywowanym module obsługi zdarzeń skopiuj następujące kody:

private void Window_Activated(object sender, EventArgs e)
{
    if (Application.Current.Windows.Count > 1)
    {
        foreach (Window win in Application.Current.Windows)
            try
            {
                if (!win.Equals(this))
                {
                    if (!win.IsVisible)
                    {
                        win.ShowDialog();
                    }

                    if (win.WindowState == WindowState.Minimized)
                    {
                        win.WindowState = WindowState.Normal;
                    }

                    win.Activate();
                    win.Topmost = true;
                    win.Topmost = false;
                    win.Focus();
                }
            }
            catch { }
    }
    else
        this.Focus();
}

Te kroki będą działać dobrze i doprowadzą do przodu wszystkie inne okna w oknie ich rodziców.

Matryca
źródło
0

Jeśli próbujesz ukryć okno, na przykład minimalizujesz okno, znalazłem to za pomocą

    this.Hide();

ukryje go poprawnie, a następnie po prostu użyje

    this.Show();

pokaże wtedy okno jako najwyżej umieszczony element.

Chris
źródło
0

Chciałem tylko dodać inne rozwiązanie do tego pytania. Ta implementacja działa w moim scenariuszu, w którym CaliBurn jest odpowiedzialny za wyświetlanie głównego okna.

protected override void OnStartup(object sender, StartupEventArgs e)
{
    DisplayRootViewFor<IMainWindowViewModel>();

    Application.MainWindow.Topmost = true;
    Application.MainWindow.Activate();
    Application.MainWindow.Activated += OnMainWindowActivated;
}

private static void OnMainWindowActivated(object sender, EventArgs e)
{
    var window = sender as Window;
    if (window != null)
    {
        window.Activated -= OnMainWindowActivated;
        window.Topmost = false;
        window.Focus();
    }
}
d.moncada
źródło
0

Pamiętaj, aby nie umieszczać kodu wyświetlającego to okno w module obsługi PreviewMouseDoubleClick, ponieważ aktywne okno powróci do okna, które obsłużyło zdarzenie. Wystarczy umieścić go w module obsługi zdarzeń MouseDoubleClick lub przestać propagować, ustawiając e.Handled na True.

W moim przypadku obsługiwałem PreviewMouseDoubleClick w widoku listy i nie ustawiałem e.Handled = true, a następnie podniosłem zdarzenie MouseDoubleClick, które skupiło się z powrotem do oryginalnego okna.

Michel P.
źródło
-1

Zbudowałem metodę rozszerzenia, aby ułatwić ponowne użycie.

using System.Windows.Forms;
    namespace YourNamespace{
        public static class WindowsFormExtensions {
            public static void PutOnTop(this Form form) {
                form.Show();
                form.Activate();
            }// END PutOnTop()       
        }// END class
    }// END namespace

Wezwij konstruktora formularzy

namespace YourNamespace{
       public partial class FormName : Form {
       public FormName(){
            this.PutOnTop();
            InitalizeComponents();
        }// END Constructor
    } // END Form            
}// END namespace
Mikrofon
źródło
Cześć Mike. Odpowiadasz na to pytanie dość późno. Czy potrafisz wyjaśnić w odpowiedzi, dlaczego to podejście różni się (a być może jest lepsze) od bardzo dobrych odpowiedzi, które zostały już opublikowane na to pytanie?
Noel Widmer
Dopiero późno, kiedy musiałem to zrobić, natknąłem się na to i chciałem podzielić się tym, jak rozwiązałem problem, który inni chcieli z niego skorzystać.
Mike
Jasne, zostałem wybrany, aby sprawdzić Twój post i chciałem Cię poinformować. Zawsze dobrze jest udzielić nowej odpowiedzi, jeśli uważasz, że jest to dobry wkład dla społeczności.
Noel Widmer
2
To pytanie dotyczyło konkretnie WPF, ale twoje rozwiązanie dotyczy WinForm.
Brian Reichle