C# 如何使用SetForeGroundIndow实现wpf启动器
我试图实现一个按钮命令,在用户第一次单击按钮时启动一个新的WPF应用程序,然后(当用户再次单击按钮时)将其发送到前台(如果它已经在运行)。整个程序都运行在C# 如何使用SetForeGroundIndow实现wpf启动器,c#,wpf,splash-screen,setforegroundwindow,C#,Wpf,Splash Screen,Setforegroundwindow,我试图实现一个按钮命令,在用户第一次单击按钮时启动一个新的WPF应用程序,然后(当用户再次单击按钮时)将其发送到前台(如果它已经在运行)。整个程序都运行在.netv4.0 当启动的进程是一个普通的WPF应用程序时,我试图做的是工作正常,正如预期的那样,但是如果启动的WPF应用程序有一个启动屏幕,它就不能很好地发挥作用。问题是,setforegroundindow失败,因为在这种特定情况下,我无法检索正确的窗口句柄。你能建议一个修复或解决方案吗?假设您可以修改启动器和已启动WPF的源 启动器视图模
.netv4.0
当启动的进程是一个普通的WPF应用程序时,我试图做的是工作正常,正如预期的那样,但是如果启动的WPF应用程序有一个启动屏幕,它就不能很好地发挥作用。问题是,setforegroundindow
失败,因为在这种特定情况下,我无法检索正确的窗口句柄。你能建议一个修复或解决方案吗?假设您可以修改启动器和已启动WPF的源
启动器视图模型中的相关代码
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;
}
假设您可以修改启动器的源和已启动的源
WPF
基于此假设,我可以确定已启动WPF应用程序的Loaded
事件中的正确句柄,并使用命名管道将其发送回启动器
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);
}
}
}
并从启动器的另一个后台工作程序中的同一命名管道读取正确的窗口句柄
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;
与
当然,我对不同的想法持开放态度
假设您可以修改启动器的源和已启动的源
WPF
基于此假设,我可以确定已启动WPF应用程序的Loaded
事件中的正确句柄,并使用命名管道将其发送回启动器
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);
}
}
}
并从启动器的另一个后台工作程序中的同一命名管道读取正确的窗口句柄
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;
与
当然,我对不同的想法持开放态度。如果您无法修改已启动的WPF应用程序,那么这只是另一种选择,但您知道其主窗口的标题标题,当然,除了流程id之外 在这种情况下,背景搜索将是
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();
使用基于进程id的筛选器
private IntPtr MainWindowHandle(Process rpt)
{
EnumWindowsProc ewp = new EnumWindowsProc(EvalWindow);
EnumWindows(ewp, new IntPtr(rpt.Id));
return mainWin;
}
以及一个测试标题标题的回调(在本例中,它是启动的
)
如果您无法修改已启动的WPF应用程序,但您知道其主窗口的标题标题,当然除了进程id之外,还有另一个选项 在这种情况下,背景搜索将是
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();
使用基于进程id的筛选器
private IntPtr MainWindowHandle(Process rpt)
{
EnumWindowsProc ewp = new EnumWindowsProc(EvalWindow);
EnumWindows(ewp, new IntPtr(rpt.Id));
return mainWin;
}
以及一个测试标题标题的回调(在本例中,它是启动的
)
我没有试过你的代码,但是已经有一些东西在那里寻找@AnjumSKhan“我没有试过你的代码”真的你表明你没有阅读,也不理解我的问题。启动的wpf已经有一个启动屏幕。我发布了这个链接,因为它可能会告诉你一些你可能缺少的东西。谢谢,但我当然知道这个链接,这正是我在我的过程中实现启动屏幕的方式。。。顺便说一句,我编辑了这个问题,以进一步说明启动屏幕在启动过程中,而不是在启动程序中(但我想这有点明显),这应该会帮助你我没有尝试你的代码,但已经有一些东西在那里寻找@AnjumSKhan“我没有尝试你的代码”你真的表明你没有阅读,也不理解我的问题。启动的wpf已经有一个启动屏幕。我发布了这个链接,因为它可能会告诉你一些你可能缺少的东西。谢谢,但我当然知道这个链接,这正是我在我的过程中实现启动屏幕的方式。。。顺便说一句,我对这个问题进行了编辑,以进一步说明启动屏幕在启动过程中,而不是在启动程序中(但我想这有点明显),这应该会对您有所帮助