Bringen Sie in WPF ein Fenster nach vorne

214

Wie kann ich meine WPF-Anwendung an die Vorderseite des Desktops bringen? Bisher habe ich versucht:

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

Keiner von Marshal.GetLastWin32Error()ihnen erledigt den Job ( besagt, dass diese Vorgänge erfolgreich abgeschlossen wurden und die P / Invoke-Attribute für jede Definition vorhanden sind SetLastError=true).

Wenn ich eine neue leere WPF-Anwendung erstelle und SwitchToThisWindowmit einem Timer aufrufe, funktioniert sie genau wie erwartet, sodass ich nicht sicher bin, warum sie in meinem ursprünglichen Fall nicht funktioniert.

Edit : Ich mache das in Verbindung mit einem globalen Hotkey.

Faktor Mystic
quelle
Haben Sie überprüft, ob MainWindow das gewünschte Fenster ist? Von MSDN: MainWindow wird automatisch mit einem Verweis auf das erste Window-Objekt festgelegt, das in der AppDomain instanziiert wird.
Todd White
Gute Gedanken, aber es ist das einzige Fenster in der Anwendung.
Factor Mystic
Können Sie etwas mehr Kontextcode geben?
Todd White

Antworten:

314
myWindow.Activate();

Versucht, das Fenster in den Vordergrund zu bringen und aktiviert es.

Das sollte den Trick machen, es sei denn, ich habe es falsch verstanden und Sie wollen immer das Top-Verhalten. In diesem Fall möchten Sie:

myWindow.TopMost = true;
Morten Christiansen
quelle
14
Ich habe einfach myWindow.Show () verwendet und manchmal war es nicht oben. Ich habe myWindow.Activate () sofort danach angerufen und es hat funktioniert.
Bermo
4
Aktivieren funktioniert manchmal nicht unter Windows XP. Ich empfehle die Antwort von @Matthew Xavier.
Lex Li
Ein bisschen seltsam, da ShowActivated standardmäßig aktiviert ist.
Greenoldman
1
Die erste Antwort ist gut, danke dafür! Die zweite Codezeile, die Verwendung der TopmostEigenschaft, ist jedoch eine schlechte Vorgehensweise, da sie andere Popup-Dialoge verdecken und unerwartetes Verhalten aufweisen kann.
Jonathan Perry
2
Tatsächlich kann dies folgendermaßen geschehen: if (myWindow.WindowState == WindowState.Minimized) myWindow.WindowState = WindowState.Normal;Seltsamerweise werden auch alle maximierten Fenster beibehalten und nicht in den normalen Zustand zurückgesetzt.
R41n
168

Ich habe eine Lösung gefunden, die das Fenster nach oben bringt, aber es verhält sich wie ein normales Fenster:

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
quelle
1
Toller Hinweis! TopMost macht die Magie unter Windows 7 möglich, wenn das Fenster bereits geöffnet ist, jedoch unter den anderen Fenstern.
gsb
Das hat auch für mich den Trick gemacht. Vielen Dank an gsb für den zusätzlichen Kommentar zu einer seltsamen Verwendung von TopMost!
Jen
1
Danke - das Update war kurz und bündig.
Code4life
2
In meinem Fall waren Window.Activate () und Window.Focus () ausreichend. Das Einstellen von Window.TopMost ist nicht erforderlich.
Virious
6
Nicht verwenden Window.Focus(). Dadurch wird der Fokus von dem entfernt, was der Benutzer gerade in ein Textfeld eingibt, was für Endbenutzer wahnsinnig frustrierend ist. Der obige Code funktioniert ohne ihn einwandfrei.
Contango
32

Wenn das Fenster beim ersten Laden vorne sein muss, sollten Sie Folgendes verwenden:

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

private void Window_Initialized(object sender, EventArgs e)
{
    this.Topmost = true;
}
Amir
quelle
1
Wenn Sie in C # etwas Ähnliches wie Launchy ( launchy.net ) entwickeln, sollten Sie feststellen, dass diese Antwort fast nutzlos ist.
Lex Li
21

So erstellen Sie ein schnelles Kopieren und Einfügen:
Verwenden Sie das DoOnProcessHauptfenster dieser Klasse, um den Prozess in den Vordergrund zu verschieben (aber nicht, um den Fokus von anderen Fenstern zu stehlen).

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
quelle
6
+1 Dies ist die einzige Antwort, die für mich nützlich war. Ich habe eine Anwendung mit einem Master und mehreren schwebenden Slave-Fenstern. Wenn Sie eines dieser Fenster aktivieren, sollten auch alle anderen Fenster nach vorne gebracht werden. Aber nicht aktiviert / Fokus erhalten, wie die meisten Antworten vermuten lassen: Dies ist eine Katastrophe, da das aktuell angeklickte Fenster nicht mehr angeklickt werden kann, da plötzlich ein anderes Fenster den Fokus erhält.
stijn
Gibt es einen Grund, es nicht zu benutzen process.MainWindowHandle?
Sriram Sakthivel
In meinem Fall wollte ich das Hauptfenster nicht, stimmte aber zu, dass es andere Möglichkeiten gibt, ein zu bekommen hWnd. FWIW ein HwndSourceObjekt hat gut funktioniert.
tobriand
21

Ich weiß, dass diese Frage ziemlich alt ist, aber ich bin gerade auf dieses genaue Szenario gestoßen und wollte die von mir implementierte Lösung teilen.

Wie in den Kommentaren auf dieser Seite erwähnt, funktionieren einige der vorgeschlagenen Lösungen nicht unter XP, was ich in meinem Szenario unterstützen muss. Obwohl ich dem Gefühl von @Matthew Xavier zustimme, dass dies im Allgemeinen eine schlechte UX-Praxis ist, gibt es Zeiten, in denen es sich durchaus um eine plausible UX handelt.

Die Lösung, um ein WPF-Fenster nach oben zu bringen, wurde mir tatsächlich durch denselben Code bereitgestellt, mit dem ich den globalen Hotkey bereitstelle. Ein Blog-Artikel von Joseph Cooney enthält einen Link zu seinen Codebeispielen , der den Originalcode enthält.

Ich habe den Code ein wenig bereinigt und geändert und ihn als Erweiterungsmethode für System.Windows.Window implementiert. Ich habe dies auf XP 32 Bit und Win7 64 Bit getestet, die beide korrekt funktionieren.

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

Ich hoffe, dieser Code hilft anderen, die auf dieses Problem stoßen.

Zodman
quelle
Hey schau mal da! Ich habe seit Monaten damit zu kämpfen! Dies funktioniert für beide Situationen. Genial! (Windows 7 x64)
mdiehl13
Eigentlich scheint es nur zu funktionieren, wenn ich das mache: App.mainWindow.Show (); SystemWindows.GlobalActivate (App.mainwindow); // Wenn ich die erste .show () entferne, wird sie nicht nach vorne gebracht
mdiehl13
+1 für SetWindowPos () suchte ich nach einer Möglichkeit, mein Fenster nur nach vorne zu bringen, ohne andere Apps zu unterbrechen oder den Fokus zu stehlen. this.Activate () stiehlt den Fokus.
Prettyvoid
Dies hat es für mich getan, und in meinem Fall ging es darum, den Fokus zu stehlen, wie es geschah, wenn ein Benutzer mit einem bestimmten Element interagierte. Vielen Dank, das scheint konsequent zu funktionieren! Nur anrufen this.Activate()scheint nur einige Male zu funktionieren.
Peter
13

Wenn der Benutzer mit einer anderen Anwendung interagiert, ist es möglicherweise nicht möglich, Ihre Anwendung in den Vordergrund zu rücken. In der Regel kann ein Prozess nur dann damit rechnen, das Vordergrundfenster festzulegen, wenn dieser Prozess bereits der Vordergrundprozess ist. (Microsoft dokumentiert die Einschränkungen im MSDN-Eintrag SetForegroundWindow () .) Dies liegt daran, dass:

  1. Der Benutzer "besitzt" den Vordergrund. Zum Beispiel wäre es äußerst ärgerlich, wenn ein anderes Programm den Vordergrund stiehlt, während der Benutzer tippt, zumindest seinen Workflow unterbricht und möglicherweise unbeabsichtigte Konsequenzen hat, da ihre für eine Anwendung bestimmten Tastenanschläge vom Täter falsch interpretiert werden, bis er die Änderung bemerkt .
  2. Stellen Sie sich vor, jedes der beiden Programme prüft, ob das Fenster der Vordergrund ist, und versucht, es in den Vordergrund zu setzen, wenn dies nicht der Fall ist. Sobald das zweite Programm ausgeführt wird, wird der Computer unbrauchbar, da der Vordergrund bei jedem Taskwechsel zwischen den beiden springt.
Matthew Xavier
quelle
Guter Punkt. Der Zweck des Codes war jedoch in Verbindung mit einem globalen Hotkey, und andere Anwendungen tun dies irgendwie.
Factor Mystic
Müssen PInvoke in C # verwenden, um zu emulieren, was in diesem Artikel beschrieben wird, codeproject.com/Tips/76427/…
Lex Li
Warum bleiben dann Fehlerüberblendungsdialogfelder für Ausdrucksmischungen sichtbar, wenn ich manchmal zu Visual Studio wechsle? : - /
Simon_Weaver
Simon, ich vermute, dass die Fehler-Popups, die Sie sehen, "oberste" Fenster sind (eine Entwurfsentscheidung, die ich ablehne). Es gibt einen Unterschied zwischen dem Vordergrundfenster (das Benutzereingaben empfängt) und einem "obersten" Fenster in der Z-Reihenfolge. Jedes Fenster kann sich selbst zum "obersten" Fenster machen, wodurch es über allen nicht obersten Fenstern platziert wird, aber die Tastatur des Fensters usw. nicht so fokussiert wie das Vordergrundfenster.
Matthew Xavier
Der Trick schlägt bei einigen speziellen Fenstern fehl. Visual Studio- und Eingabeaufforderungsfenster müssen etwas enthalten, das verhindert, dass andere Fenster zum Vordergrundfenster werden.
Lex Li
9

Ich weiß, dass dies eine späte Antwort ist, vielleicht hilfreich für Forscher

 if (!WindowName.IsVisible)
 {
     WindowName.Show();
     WindowName.Activate();
 }
Jamaxack
quelle
9

Warum einige der Antworten auf dieser Seite falsch sind!

  • Jede Antwort, die verwendet window.Focus()wird , ist falsch.

    • Warum? Wenn eine Benachrichtigungsnachricht angezeigt wird, window.Focus()wird der Fokus von dem entfernt, was der Benutzer gerade eingibt. Dies ist für Endbenutzer wahnsinnig frustrierend, insbesondere wenn die Popups ziemlich häufig auftreten.
  • Jede Antwort, die verwendet window.Activate()wird , ist falsch.

    • Warum? Dadurch werden auch alle übergeordneten Fenster sichtbar.
  • Jede Antwort, die weggelassen window.ShowActivated = falsewird , ist falsch.
    • Warum? Es wird den Fokus von einem anderen Fenster wegnehmen, wenn die Nachricht erscheint, was sehr ärgerlich ist!
  • Jede Antwort, die nicht Visibility.Visiblezum Ausblenden / Anzeigen des Fensters verwendet wird, ist falsch.
    • Warum? Wenn wir Citrix verwenden und das Fenster beim Schließen nicht ausgeblendet wird, bleibt ein seltsamer schwarzer rechteckiger Griff auf dem Bildschirm. So können wir nicht verwenden , window.Show()und window.Hide().

Im Wesentlichen:

  • Das Fenster sollte den Fokus bei Aktivierung nicht von anderen Fenstern wegnehmen.
  • Das Fenster sollte sein übergeordnetes Fenster nicht aktivieren, wenn es angezeigt wird.
  • Das Fenster sollte mit Citrix kompatibel sein.

MVVM-Lösung

Dieser Code ist 100% kompatibel mit Citrix (keine leeren Bereiche des Bildschirms). Es wird sowohl mit normalem WPF als auch mit DevExpress getestet.

Diese Antwort ist für jeden Anwendungsfall vorgesehen, in dem ein kleines Benachrichtigungsfenster angezeigt werden soll, das sich immer vor anderen Fenstern befindet (sofern der Benutzer dies in den Einstellungen auswählt).

Wenn diese Antwort komplexer erscheint als die anderen, liegt dies daran, dass es sich um robusten Code auf Unternehmensebene handelt. Einige der anderen Antworten auf dieser Seite sind einfach, funktionieren aber nicht.

XAML - Angehängte Eigenschaft

Fügen Sie diese angehängte Eigenschaft zu einem beliebigen UserControlElement im Fenster hinzu. Die beigefügte Eigenschaft wird:

  • Warten Sie, bis das LoadedEreignis ausgelöst wird (andernfalls kann der visuelle Baum nicht nachgeschlagen werden, um das übergeordnete Fenster zu finden).
  • Fügen Sie einen Ereignishandler hinzu, der sicherstellt, dass das Fenster sichtbar ist oder nicht.

Sie können das Fenster jederzeit so einstellen, dass es vorne ist oder nicht, indem Sie den Wert der angehängten Eigenschaft umdrehen.

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

C # - Hilfsmethode

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".
        }
    }
}

Verwendung

Um dies zu verwenden, müssen Sie das Fenster in Ihrem ViewModel erstellen:

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

Zusätzliche Links

Tipps, wie Sie sicherstellen können, dass ein Benachrichtigungsfenster immer wieder auf den sichtbaren Bildschirm verschoben wird , finden Sie in meiner Antwort: Wie kann in WPF ein Fenster auf den Bildschirm verschoben werden, wenn es nicht auf dem Bildschirm angezeigt wird? .

Contango
quelle
5
"Code auf Unternehmensebene" und einige Zeilen später catch (Exception) { }. Ja, richtig ... und es wird Code verwendet, der in der Antwort nicht einmal wie _dialogServiceoder angezeigt wird ShiftWindowOntoScreenHelper. Außerdem bitten Sie darum, das Fenster auf der Seite des Ansichtsmodells zu erstellen (was im Grunde das gesamte MVVM-Muster bricht) ...
Kryptos
@Kryptos Dies ist Code auf Unternehmensebene. Ich habe es aus dem Speicher getippt, und genau diese Technik wird in einer großen FTSE100-Firma verwendet. Das wirkliche Leben ist etwas weniger makellos als die perfekten Designmuster, die wir alle anstreben.
Contango
Ich mag die Tatsache nicht, dass wir selbst eine Instanz des Fensters im Ansichtsmodell behalten, wie Kryptos erwähnte, das den ganzen Sinn von mvvm bricht. Vielleicht hätte es stattdessen in Codebehind gemacht werden können?
Igor Meszaros
1
@Igor Meszaros Einverstanden. Jetzt, da ich mehr Erfahrung habe, würde ich, wenn ich es noch einmal tun müsste, ein Verhalten hinzufügen und es mit einem steuern, Func<>das an das ViewModel gebunden ist.
Contango
7

Ich hatte ein ähnliches Problem mit einer WPF-Anwendung, die von einer Access-Anwendung über das Shell-Objekt aufgerufen wird.

Meine Lösung ist unten - funktioniert in XP und Win7 x64 mit App auf x86-Ziel kompiliert.

Ich würde das viel lieber tun, als einen Alt-Tab zu simulieren.

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

Nun, da dies ein so heißes Thema ist ... hier ist, was für mich funktioniert. Ich habe Fehler erhalten, wenn ich es nicht so gemacht habe, weil Activate () bei Ihnen einen Fehler macht, wenn Sie das Fenster nicht sehen können.

Xaml:

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

Codebehind:

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

Dies war der einzige Weg für mich, das Fenster oben zu zeigen. Aktivieren Sie es dann, damit Sie das Feld eingeben können, ohne den Fokus mit der Maus einstellen zu müssen. control.Focus () funktioniert nur, wenn das Fenster Active () ist.

Omzig
quelle
2

Nun, ich habe eine Lösung gefunden. Ich rufe über einen Tastatur-Hook an, mit dem ein Hotkey implementiert wird. Der Aufruf funktioniert wie erwartet, wenn ich ihn mit einer Pause in einen BackgroundWorker stelle. Es ist ein Kludge, aber ich habe keine Ahnung, warum es ursprünglich nicht funktioniert hat.

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();
}
Faktor Mystic
quelle
Nur interessiert: Haben Sie Window.Activate (wie von Morten vorgeschlagen) und die anderen Vorschläge ausprobiert? Sie scheinen weniger hackig als dieser zugegebene Kludge.
Simon D.
Das ist schon eine ganze Weile her, aber ja, zu der Zeit, als ich das versucht habe
Factor Mystic
Dies funktioniert unter Windows XP nicht. Ich empfehle die Antwort von @Matthew Xavier.
Lex Li
2

Um JEDES aktuell geöffnete Fenster anzuzeigen, importieren Sie diese 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);

und im Programm Wir suchen nach App mit angegebenem Titel (Titel ohne Anfangsbuchstaben schreiben (Index> 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
quelle
"Titel Ihrer App OHNE ERSTEN BRIEF" Oof, hacky hacky hacky. Warum nicht IndexOfstattdessen richtig verwenden?
Leichtigkeitsrennen im Orbit
1

Das Problem könnte sein, dass der Thread, der Ihren Code vom Hook aus aufruft, nicht von der Laufzeit initialisiert wurde, sodass das Aufrufen von Laufzeitmethoden nicht funktioniert.

Vielleicht könnten Sie versuchen, einen Aufruf durchzuführen, um Ihren Code im UI-Thread zu marshallen und Ihren Code aufzurufen, der das Fenster in den Vordergrund rückt.

Joshperry
quelle
1

Diese Codes funktionieren immer einwandfrei.

Stellen Sie zunächst den aktivierten Event-Handler in XAML ein:

Activated="Window_Activated"

Fügen Sie Ihrem Konstruktionsblock für das Hauptfenster die folgende Zeile hinzu:

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

Und kopieren Sie im aktivierten Event-Handler die folgenden Codes:

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

Diese Schritte funktionieren einwandfrei und bringen alle anderen Fenster in das Fenster ihrer Eltern.

Matrix
quelle
0

Wenn Sie versuchen, das Fenster auszublenden, zum Beispiel das Fenster zu minimieren, habe ich festgestellt, dass mit

    this.Hide();

wird es richtig ausblenden, dann einfach mit

    this.Show();

Anschließend wird das Fenster erneut als oberstes Element angezeigt.

Chris
quelle
0

Ich wollte nur eine weitere Lösung für diese Frage hinzufügen. Diese Implementierung funktioniert für mein Szenario, in dem CaliBurn für die Anzeige des Hauptfensters verantwortlich ist.

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

Denken Sie daran, den Code, der dieses Fenster anzeigt, nicht in einen PreviewMouseDoubleClick-Handler einzufügen, da das aktive Fenster wieder zu dem Fenster wechselt, das das Ereignis behandelt hat. Legen Sie es einfach in den MouseDoubleClick-Ereignishandler oder stoppen Sie das Sprudeln, indem Sie e.Handled auf True setzen.

In meinem Fall habe ich den PreviewMouseDoubleClick in einer Listenansicht verarbeitet und nicht e.Handled = true gesetzt, dann wurde das MouseDoubleClick-Ereignis ausgelöst, bei dem der Fokus wieder auf das ursprüngliche Fenster gerichtet war.

Michel P.
quelle
-1

Ich habe eine Erweiterungsmethode entwickelt, um die Wiederverwendung zu vereinfachen.

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

Rufen Sie den Formularkonstruktor auf

namespace YourNamespace{
       public partial class FormName : Form {
       public FormName(){
            this.PutOnTop();
            InitalizeComponents();
        }// END Constructor
    } // END Form            
}// END namespace
Mike
quelle
Hallo Mike. Sie beantworten diese Frage ziemlich spät. Können Sie in Ihrer Antwort erklären, warum sich dieser Ansatz von den sehr guten Antworten unterscheidet (und vielleicht sogar besser), die bereits für diese Frage veröffentlicht wurden?
Noel Widmer
Erst spät, als ich dies nur tun musste, und ich stieß darauf und wollte mitteilen, wie ich das Problem gelöst habe, wenn andere es verwenden wollten.
Mike
Klar, ich wurde ausgewählt, um Ihren Beitrag zu überprüfen und wollte Sie darauf aufmerksam machen. Es ist immer gut, eine neue Antwort zu geben, wenn Sie der Meinung sind, dass dies ein guter Beitrag für die Community ist.
Noel Widmer
2
Diese Frage betraf speziell WPF, aber Ihre Lösung ist für WinForms.
Brian Reichle