2017-03-18 5 views
1

Ich versuche, einen Button-Befehl zu implementieren, der eine neue WPF-Anwendung startet, wenn der Benutzer zum ersten Mal auf die Schaltfläche klickt und dann (wenn der Benutzer die Schaltfläche erneut klickt) an den Vordergrund sendet. wenn es bereits läuft. Das Ganze läuft auf .Net v4.0So implementieren Sie einen WPF-Launcher mit SetForegroundWindow

Was ich versucht habe, in Ordnung zu tun, funktioniert, wie erwartet, wenn der gestartete Prozess eine normale WPF-Anwendung ist, aber es ist nicht schön zu spielen, wenn die WPF-Anwendung gestartet hat ein Begrüßungsbildschirm. Das Problem ist, dass SetForegroundWindow fehlschlägt, da ich das richtige Fensterhandle in diesem bestimmten Fall nicht abrufen kann. Können Sie eine Reparatur oder einen Work-Around vorschlagen? Angenommen, Sie können die Quelle sowohl des Startprogramms als auch des gestarteten WPF ändern.

Der entsprechende Code aus dem View-Modell des Launchers

private void ClaimRptLogic() 
    { 
     if (ClaimRptHandle != IntPtr.Zero) 
     { 
      ShowWindow(ClaimRptHandle, SW_RESTORE); 
      LaunchState = SetForegroundWindow(ClaimRptHandle)? "" : "can't set to foreground"; 
      return; 
     } 

     Process rpt = new Process(); 
     rpt.StartInfo = new ProcessStartInfo() 
     { 
      WorkingDirectory = ConfigurationManager.AppSettings["ClaimRptPath"], 
      FileName = ConfigurationManager.AppSettings["ClaimRptexe"] 
     }; 
     rpt.Start(); 
     BackgroundWorker bg = new BackgroundWorker(); 
     bg.DoWork += new DoWorkEventHandler((o, e) => { 
      rpt.WaitForExit(); 
     }); 
     bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler((o, e) => { 
      ClaimRptHandle = IntPtr.Zero; 
      LaunchState = "ClaimRpt closed"; 
     }); 
     bg.RunWorkerAsync(); 
     Thread.Sleep(3000); 
     ClaimRptHandle = rpt.MainWindowHandle; 
    } 
+0

Ich habe Ihren Code nicht versucht, aber es gibt etwas schon da draußen zu suchen nach https: // m sdn.microsoft.com/en-us/library/cc656886(v=vs.110).aspx – AnjumSKhan

+1

@AnjumSKhan "* Ich habe deinen Code nicht versucht *" Du hast wirklich gezeigt, dass du nicht gelesen hast und du nicht verstehe meine Frage. Der ** gestartete ** wpf hat bereits einen Begrüßungsbildschirm. –

+0

Ich habe diesen Link gepostet, da er Ihnen etwas mitteilen könnte, was Ihnen vielleicht fehlt. – AnjumSKhan

Antwort

0

Angenommen, Sie die Quelle sowohl den Launcher ändern können und die gestarteten WPF.

Basierend auf dieser Annahme, kann ich den richtigen Griff in dem Loaded Ereignisse der gestarteten WPF-Anwendung bestimmen und es zurück an den Launcher mit einem Named Pipe senden.

private void Window_Loaded(object sender, RoutedEventArgs e) 
{ 
    var callback = new WindowInteropHelper(this).Handle; 
    BackgroundWorker bg = new BackgroundWorker(); 
    bg.DoWork += (s, a) => 
    { 
     WritePipe("at loaded evt: " + callback); 
    }; 
    bg.RunWorkerAsync(); 
} 

private void WritePipe(string line) 
{ 
    using (NamedPipeServerStream server = 
     new NamedPipeServerStream(Environment.UserName, PipeDirection.InOut)) 
    { 
     server.WaitForConnection(); 
     using (StreamWriter sw = new StreamWriter(server)) 
     { 
      sw.WriteLine(line); 
     } 
    } 
} 

und den richtigen Fenstergriff aus dem gleichen Named Pipe in einem anderen Hintergrund Arbeitern der

bg.RunWorkerAsync(); 
Thread.Sleep(3000); 
if (rpt.HasExited) 
{ 
    return; 
} 
LaunchedHandle = rpt.MainWindowHandle; 
BackgroundWorker bgPipe = new BackgroundWorker(); 
bgPipe.DoWork += new DoWorkEventHandler((o, e) => { 
    while (!rpt.HasExited) 
    { 
     string testHandle = ReadPipe(); 
     if (testHandle.StartsWith("at loaded evt: ")) 
     { 
      Debug.WriteLine(testHandle); 
      Debug.WriteLine("CallBack from Launched Process!"); 
      var handle = testHandle.Replace("at loaded evt: ",""); 
      LaunchedHandle = new IntPtr(int.Parse(handle)); 
      return; 
     } 
     LaunchedHandle = rpt.MainWindowHandle; 
     Thread.Sleep(500); 
    } 
    Debug.WriteLine("Process exited!"); 
}); 
bgPipe.RunWorkerAsync(); 
CanLaunchCmd = true; 

mit

private string ReadPipe() 
{ 
    string line = ""; 
    using (NamedPipeClientStream client = 
     new NamedPipeClientStream(".", Environment.UserName, PipeDirection.InOut)) 
    { 
     client.Connect(); 
     using (StreamReader sr = new StreamReader(client)) 
     { 
      line = sr.ReadLine(); 
     } 
     return line; 
    } 
} 

Natürlich Launcher lesen, ich bin offen für verschiedene Ideen .

0

Nur eine weitere Option, wenn Sie die gestartete WPF-App nicht ändern können, aber Sie kennen die Titelleiste ihres Hauptfensters neben der Prozess-ID natürlich.

In diesem Fall würde die Hintergrundsuche

LaunchedHandle = rpt.MainWindowHandle; 
mainWin = rpt.MainWindowHandle; 
BackgroundWorker bgTitle = new BackgroundWorker(); 
bgTitle.DoWork += new DoWorkEventHandler((o, e) => { 
while (!rpt.HasExited) 
    { 

     LaunchedHandle = MainWindowHandle(rpt); 
     Thread.Sleep(500); 
    } 
    Debug.WriteLine("Process exited!"); 
}); 
bgTitle.RunWorkerAsync(); 

unter Verwendung eines Filters auf der Basis der Prozess-ID

private IntPtr MainWindowHandle(Process rpt) 
{ 
    EnumWindowsProc ewp = new EnumWindowsProc(EvalWindow); 
    EnumWindows(ewp, new IntPtr(rpt.Id)); 
    return mainWin; 
} 

und einen Rückruf, um die Titel Beschriftung Prüfung sein (in diesem Beispiel ist es Launched)

Verwandte Themen