Window: BringToFront ohne Activate?

  • WPF

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von BjöNi.

    Window: BringToFront ohne Activate?

    Hallo,
    ich fange z. Zt. mit WPF an (um ehrlich zu sein: bis jetzt hat es mich noch nicht wirklich überzeugt...).

    Ich möchte ein Fenster nach vorne bringen, ohne es zu aktivieren. In VB.NET war das mit BringToFront() möglich, in WPF gibt es dies nicht mehr.
    Google sagt immer nur für Controls, dass diese mithilfe von SetZIndex(...) bewegt werden können, Fenster mit Activate() nach vorne gebracht werden können. Dies fokussiert das Fenster aber gleich.

    Alternativ wäre für mich auch eine Möglichkeit, wenn es irgendeine Methode gibt, die ein Fenster dauerhaft vorne hält. Also auch vor der Taskleiste, wenn der User z.B. +D drückt.

    Kennt jemand so etwas?
    Mfg, BjöNi
    Ich sehe absolut rein gar keinen Sinn darin ein Fenster nach vorne zu bringen aber nicht den Focus zu geben. Ansonsten findest hier fast alles was es gibt: stackoverflow.com/questions/25…indow-to-the-front-in-wpf

    Btw. das ist das Erste google Ergebnis. Und hier findest du auch wie du das Fenster nach vorne bringst ohne Focus.

    Was das Win+D angeht: Nö. Musste selbstständig wieder nach vorne bringen. Win+D minimiert alles.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.

    thefiloe schrieb:

    Ich sehe absolut rein gar keinen Sinn darin ein Fenster nach vorne zu bringen aber nicht den Focus zu geben.
    Für eine Infomeldung z.B. wäre es imo sinnvoll. Sollte der User gerade am Tippen sein, so sollte das alte Fenster dennoch den Focus behalten.

    thefiloe schrieb:

    Btw. das ist das Erste google Ergebnis. Und hier findest du auch wie du das Fenster nach vorne bringst ohne Focus.
    Da war ich schon. Bei der Antwort von Hertzel Guinness steht zwar dabei "move process' main window to foreground (but not to steal focus from other windows)", kriegt den Focus aber trotzdem.

    big-d schrieb:

    Leicht verändert (und nach VB.Net konvertiert) kannste auch folgendes verwenden:
    Danke, werd ich mir mal anschauen. Eigentlich wollte ich das Fenster aber gerne vor der Taskleiste halten, aber mal schauen...

    big-d schrieb:

    Ausserdem kannste Dir mal die API SetWindowPos ansehen.
    Hab ich auch schon mit rumprobiert, kriegt aber immer den Focus oder gar nichts...

    BjöNi schrieb:

    Hab ich auch schon mit rumprobiert, kriegt aber immer den Focus oder gar nichts...
    Wenn big-D's Code funktioniert solltest Du unbedingt den nehmen, da API's nicht mehr unbedingt in die verwaltete .NET Welt gehören.

    Ansonsten geht folgender, nicht besonders eleganter Code:

    VB.NET-Quellcode

    1. Private Sub SetWindowToTopWithoutFocus(ByVal hwnd As IntPtr)
    2. Dim HWND_TOPMOST As New IntPtr(-1) : Dim HWND_NOTOPMOST As New IntPtr(-2)
    3. Const SWP_NOACTIVATE As Integer = &H10 : Const SWP_NOMOVE As Integer = &H2 : Const SWP_NOSIZE As Integer = &H1
    4. SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOACTIVATE)
    5. SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOACTIVATE)
    6. End Sub
    7. ' API
    8. Public Declare Auto Function SetWindowPos Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As UInt32) As Boolean

    Als ich den Code verwendete hatte ich auch keinen anderen Ausweg gefunden als das Fenster kurzfristig auf Topmost zu setzen. Vielleicht funktioniert es auch einfacher mit der Forms.Topmost Property, - ich habs nicht ausprobiert.
    Ich habe nun folgenden Code zusammengebastelt:

    VB.NET-Quellcode

    1. <DllImport("user32.dll")> _
    2. Public Shared Function FindWindow(lpClassName As String, lpWindowName As String) As IntPtr
    3. End Function
    4. <DllImport("user32.dll")> _
    5. Public Shared Function SetParent(hWndChild As IntPtr, hWndNewParent As IntPtr) As IntPtr
    6. End Function
    7. Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
    8. SetParent(New Interop.WindowInteropHelper(Me).Handle, FindWindow("Shell_TrayWnd", Nothing))
    9. End Sub
    Ich dachte, wenn ich den Tray als Parent setze, sollte das Fenster ja immer im Vordergrund sein. Ist es aber nicht (verschwindet einfach). Ich werde mich in den nächsten Tagen nochmal damit beschäftigen.
    Wie kommst du auf SetParent?
    Ich kann nur eines sagen: In WinForms wird das auch über SetWindowPos gemacht(also die BringToFront() Methode):

    VB.NET-Quellcode

    1. If Me.IsHandleCreated AndAlso Me.GetTopLevel() AndAlso SafeNativeMethods.IsWindowEnabled(New HandleRef(Me.window, Me.Handle)) Then
    2. SafeNativeMethods.SetWindowPos(New HandleRef(Me.window, Me.Handle), NativeMethods.HWND_TOP, 0, 0, 0, 0, 3)
    3. End If



    Von dem her wirste das wohl oder übel auch so machen müssen.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „thefiloe“ ()

    BjöNi schrieb:

    Ich dachte, wenn ich den Tray als Parent setze, sollte das Fenster ja immer im Vordergrund sein.

    Deshalb. Der Tray ist ja auch immer im Vordergrund. Eigentlich will ich das Fenster auch wie oben beschrieben vor der Taskleiste haben.
    Hab dir oben noch editiert. Du kommst nicht um SetWindowPos rum.

    Ach ja:

    BjöNi schrieb:

    In VB.NET war das mit BringToFront() möglich, in WPF gibt es dies nicht mehr.
    VB.NET ist NICHT WinForms. WPF ist genauso VB.NET wie Winforms,...


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.

    thefiloe schrieb:

    VB.NET ist NICHT WinForms. WPF ist genauso VB.NET wie Winforms,...
    Stimmt -.- Hab ich nicht nachgedacht.

    thefiloe schrieb:

    Hab dir oben noch editiert. Du kommst nicht um SetWindowPos rum.
    Aber ich kriege es trotzdem nicht hin, das vor der Taskleiste zu halten.
    Bekommst du es denn mit WinForms hin?
    Muss sagen, ich hab so Zeug nie gebraucht. Aber das vor der Taskleiste ist doch auch immer etwas buggy? Und wenn du natürlich Win+D drückst musst du natürlich das Ganze wieder aufrufen und möglicherweise von minimierten Zustand wieder in den normalen Zustand befördern. Ich weiß jedoch nicht genau was passiert wenn man Win+D drückt.

    Kann nur sagen: So machts Winforms und das wird wohl auch so der einzige Weg sein. Wenn Microsoft ihre WinAPI nicht kennt,... wer dann?


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Mit Winforms hatte ich es immerhin soweit, dass das BringToFront() das Fenster nur nach vorne verschoben, nicht fokussiert hat. In dem sehr unperformanten TrayDrop (wie ich dort auch geschrieben habe) wird in einem extra Thread alle 100ms BringToFront aufgerufen. Das hatte ich eben vor neu mit WPF aufzusetzen. Auch mit einem gescheiteren Pluginsystem, aber das ist eine andere Baustelle.
    Das Problem war, dass ich wohl irgendwas anderes im Projekt falsch hatte. Mit folgendem Code klappt es nun in einem Testrojekt:

    VB.NET-Quellcode

    1. Class MainWindow
    2. Public Declare Auto Function SetWindowPos Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As UInt32) As Boolean
    3. Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
    4. Topmost = True
    5. With New System.Threading.Thread(Sub()
    6. Do
    7. Dispatcher.Invoke(Sub()
    8. SetWindowPos(New Interop.WindowInteropHelper(Me).Handle, New IntPtr(0), 0, 0, 0, 0, 3)
    9. End Sub)
    10. System.Threading.Thread.Sleep(1000)
    11. Loop
    12. End Sub)
    13. .Start()
    14. End With
    15. End Sub
    16. End Class
    (ich weiß, ranzige API-Deklaration...)

    Außerdem hatte ich mich noch an @big-d:s Code versucht, habs aber nicht hinbekommen. Dort wird ja auch die Form als Child von "ProgMan" gesetzt.

    ErfinderDesRades schrieb:

    das ist jetzt doppelt gemoppelt, da du sowohl TopMost anwendest als auch SetWindowPos.
    Nope, ist es nicht. Habe ich bereits ausprobiert. Ich benötige ein Fenster, das sich vor der Taskleiste halten kann.

    ErfinderDesRades schrieb:

    Auch der Einsatz des Threads ist evtl. ganz unnötig.
    Mag sein: Nen Timer oder Backgroundworker tät's vielleicht auch, aber was spricht gegen einen Thread?
    OK, die letzten beiden Punkte haben mich überzeugt. Werd's demnächst gegen einen Timer austauschen. ;)