Laden...

Eigene Applikation im Vordergrund, aber Fokus auf der unterliegenden Applikation behalten

Erstellt von Crobest vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.189 Views
C
Crobest Themenstarter:in
1 Beiträge seit 2019
vor 4 Jahren
Eigene Applikation im Vordergrund, aber Fokus auf der unterliegenden Applikation behalten

Hallo liebes Forum, ich bin neu hier im Forum und auch ein Neuling in C#.

Zu meinem aktuellen Vorhaben: Momentan versuche ich eine kleine WPF Applikation zu erstellen, welche kurze aber wichtige Infos für mich bereit hält - Ähnlich der Windows (10) Notizen App. Meine App soll zusätzlich Buttons haben, womit ich zwischen den Infos blättern kann.

Der Unterschied zur Windows Notizen App wäre, dass meine App immer im Vordergrund sein soll. Zusätzlich soll aber der Fokus von der dahinter liegende Applikation nicht weg genommen werden (Egal welche App dahinter ist!).

Vom Ablauf her, stelle ich mir das folgendermaßen vor: Es laufen beliebig viele App's auf dem Rechner und z.B.: die Windows Explorer App ist im Vordergrund und hat den Fokus. Jetzt starte ich meine App, diese erscheint im Vordergrund hat aber nicht den Fokus. Dann blätter ich in meiner App zur benötigten Info und der Fokus bleibt bzw. kehrt zu der App zurück, welche es davor hatte - in diesem Fall: die Windows Explorer App. Dort kann man dann weiter arbeiten, ohne 2x Klicken zu müssen.

Das meine App im Vordergrund gestartet wird und auch bleibt, habe ich in der MainWindow.xaml mit

Topmost="True"

realisiert.
Das meine App beim Start nicht den Fokus erhält, habe ich in der MainWindow.xaml mit

ShowActivated auf "False"

realisiert.

Soweit so gut - die App startet, ist im Vordergrund, die Windows Explorer App behält den Fokus.
Das Problem entsteht beim Blättern bzw. beim Button betätigen. Sobald ich den Button in meiner App drücke, kriegt meine App den Fokus und ich muss z.B.: beim Windows Explorer 2x klicken, um z.B.: einen Button von der Explorer App zu betätigen (1 Klick = Fokus auf Explorer App setzen, 2 Klick = Button betätigen).

Das würde ich gerne verhindern, aber ich krieg es momentan nicht hin, das alle App's den Fokus zurück erhalten. Ich habe viel im Internet und auch hier im Forum recherchiert - einige Codes ausprobiert. Mein aktueller Ansatz ist: Beim Start (später dann auch vor jedem Buttonklick) zu schauen, welche App aktuell im Vordergrund ist, den Namen der App zu speichern und diese dann nach dem Buttonklick (in meiner App) wieder in den Vordergrund zu holen.

Wenn ich das ganze mit dem Windows Editor teste - klappt es, die Windows Editor App kriegt den Fokus zurück. Doch beim Windows Explorer oder beim Chrome Browser klappt es nicht - der Fokus landet irgendwo - Die Schriftfarbe vom Titel der App wird ja beim Fokusverlust von Schwarz nach Grau geändert - man sieht das sowohl der Titel meiner App, als auch der Titel vom Windows Explorer auf Grau geändert wird.
Teste ich es mit Visual Studio, verkleinert sich das Fenster von Visual Studio...aber es erhält den Fokus.

Von daher Frage ich mich, ob mein Ansatz generell ein guter oder vllt. der richtige Ansatz ist - oder gibt es eine Alternative die zuverlässiger laufen würde? habe ich vllt. einen Fehler drin, so das manche App's gehen, manche aber nicht?

Hier meine Code:

MainWindow.xaml


<Window x:Class="test1.MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:local="clr-namespace:test1"
  mc:Ignorable="d"
  Title="MainWindow" 
  Height="200" 
  Width="400"
  Left="500"
  Top="500"
  VerticalAlignment="Center"
  HorizontalAlignment="Center"
  WindowStyle="SingleBorderWindow"
  Topmost="True" 
  Focusable="False" 
  ShowActivated="False">
    <Grid>
        <Button Click="Button_Click"  
                Width="100" Height="30" 
                HorizontalAlignment="Right" 
                VerticalAlignment="Bottom">
            Test starten
        </Button>
        <TextBox HorizontalAlignment="Left" 
                 Text="Infotext: Hier stehen später hilfreiche Tipps und Infos." 
                 VerticalAlignment="Top" 
                 Width="400" 
                 Height="100"/>
    </Grid>
</Window>

MainWindow.xaml.cs


using System;
using System.Linq;
using System.Windows;
using System.Runtime.InteropServices;
using System.Diagnostics;


namespace test1
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        string pname;

        [DllImport("User32.dll")]
        static extern int SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        internal static extern bool SendMessage(IntPtr hWnd, Int32 msg, Int32 wParam, Int32 lParam);
        static Int32 WM_SYSCOMMAND = 0x0112;
        static Int32 SC_RESTORE = 0xF120;

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

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern Int32 GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

        private string GetForegroundProcessName()
        {
            IntPtr hwnd = GetForegroundWindow();

            if (hwnd == null)
                return "Unknown";

            GetWindowThreadProcessId(hwnd, out uint pid);

            foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses())
            {
                if (p.Id == pid)
                {
                    pname = p.ProcessName.ToString();
                    MessageBox.Show("pname: " + pname).ToString();
                }
            }

            return "Unknown";
        }

        public MainWindow()
        {
            InitializeComponent();
            GetForegroundProcessName();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var proc = Process.GetProcessesByName(pname).FirstOrDefault();
            MessageBox.Show(proc.ToString());

            if (proc != null)
            {
                
                var pointer = proc.MainWindowHandle;
                MessageBox.Show(pointer.ToString());
                SetForegroundWindow(pointer);
                SendMessage(pointer, WM_SYSCOMMAND, SC_RESTORE, 0);
            }
        }
    }
}


Der Test mit dem Windows Editor ergibt:
p.ProcessName = notepad
proc = System.Diagnostics.Process (notepad)
pointer = 9437248

Der Test mit dem Windows Explorer ergibt:
p.ProcessName = explorer
proc = System.Diagnostics.Process (explorer)
pointer = 131240

Der Test mit dem Google Chrome ergibt:
p.ProcessName = chrome
proc = System.Diagnostics.Process (chrome)
pointer = 0

Der Test mit Visual Studio 2017 ergibt:
p.ProcessName = devenv
proc = System.Diagnostics.Process (devenv)
pointer = 2360162

Ich freue mich über jede Hilfe und hoffe Ihr habt nachsicht mit mir, wenn ich was falsch gepostet habe o.ä.

Schöne Grüße
Crobest

16.806 Beiträge seit 2008
vor 4 Jahren

Der Unterschied zur Windows Notizen App wäre, dass meine App immer im Vordergrund sein soll. Zusätzlich soll aber der Fokus von der dahinter liegende Applikation nicht weg genommen werden

Sobald ich den Button in meiner App drücke, kriegt meine App den Fokus

Ich meine, dass ich genau dieses Wunschverhalten schon viele viele Male gelesen habe, das in der Form aufgrund des Fernsterverhaltens des Betriebssystem jedoch leider gar nicht möglich ist; weil eben das Window Management hier den Fokus wechselt und Du dies nicht aktiv beeinflussen kannst.

2.078 Beiträge seit 2012
vor 4 Jahren

In den Raum geraten:

Könnte die Anwendung nicht regelmäßig nach fragen, wer den Fokus hat und dann, wenn sie den Fokus bekommt, ihn wieder zurück setzen?
Oder, sie kann beim Fokus-Wechsel abfragen, wer vorher den Fokus hatte.

Ist aber nur eine Idee, ich hab keine Ahnung, ob das funktioniert.

S
248 Beiträge seit 2008
vor 4 Jahren

Ich meine, dass ich genau dieses Wunschverhalten schon viele viele Male gelesen habe, das in der Form aufgrund des Fernsterverhaltens des Betriebssystem jedoch leider gar nicht möglich ist; weil eben das Window Management hier den Fokus wechselt und Du dies nicht aktiv beeinflussen kannst.

Diese stehen in der Remarks Section von SetForgroundWindow.

Grüße

4.931 Beiträge seit 2008
vor 4 Jahren

Unter WinForms ist es recht einfach ein "unfokussierbares" Window zu öffnen: Eine unfocusierbares Form realisieren (d.h. dies ist ein WinAPI-Feature).

Ich weiß jetzt nur nicht auf die Schnelle, inwieweit man bei WPF in den "Create Window"-Prozess eingreifen kann?