C# 启动外部进程并在其完成后设置值

C# 启动外部进程并在其完成后设置值,c#,wpf,event-handling,C#,Wpf,Event Handling,我正在开发一个WPF应用程序,它被设置为始终是最上面的窗口。我在这个应用程序中添加了一个按钮,它启动一个外部程序,允许用户校准我们用户将要与之交互的触摸屏显示器 我可以关闭主窗口的最高设置并启动我的应用程序,但我需要能够在这个外部应用程序退出后将主窗口的最高设置设置为true 有人建议我在启动流程时添加一个事件处理程序,在流程结束时可以重置最顶层。事件处理程序对我来说是新的,所以我不知道该怎么做。有人能陪我走过吗 下面是我目前在主窗口中禁用topmost并启动应用程序的代码。到目前为止没什么大不

我正在开发一个WPF应用程序,它被设置为始终是最上面的窗口。我在这个应用程序中添加了一个按钮,它启动一个外部程序,允许用户校准我们用户将要与之交互的触摸屏显示器

我可以关闭主窗口的最高设置并启动我的应用程序,但我需要能够在这个外部应用程序退出后将主窗口的最高设置设置为true

有人建议我在启动流程时添加一个事件处理程序,在流程结束时可以重置最顶层。事件处理程序对我来说是新的,所以我不知道该怎么做。有人能陪我走过吗

下面是我目前在主窗口中禁用topmost并启动应用程序的代码。到目前为止没什么大不了的

            Application.Current.MainWindow.Topmost = false;
            System.Diagnostics.Process.Start(@"C:\path\to\app.exe");
非常感谢


(本周末我将阅读事件处理程序和委托!)

创建流程,将EnableRaisingEvents设置为true,并处理退出的
事件:

Process p = new Process();
p.StartInfo.FileName = pathToApp;
p.EnableRaisingEvents = true;
p.Exited += OnCalibrationProcessExited;  // hooks up your handler to the Process
p.Start();

// Now .NET will call this method when the process exits
private void OnCalibrationProcessExited(object sender, EventArgs e)
{
  // set Topmost
}
从comments线程中,将在工作线程上引发退出事件,因此您需要使用Dispatcher.BeginInvoke切换到UI线程以设置最顶层:

private void OnCalibrationProcessExited(object sender, EventArgs e)
{
  Action action = () => { /* set Topmost */ };
  Dispatcher.BeginInvoke(DispatcherPriority.Normal, action);
}
(这假设代码在窗口类中。如果不是,则需要编写类似于
Application.Current.MainWindow.Dispatcher.BeginInvoke(…)
的代码。)


注意:我已将创建和配置Process对象与启动它分开。虽然这更为详细,但必须确保在流程启动之前所有事件处理内容都已准备就绪——否则流程可能会在您放置处理程序之前退出(不太可能,但理论上可能!),并且您的处理程序将永远不会被调用。

创建流程,将EnableRaisingEvents设置为true并处理退出的
事件:

Process p = new Process();
p.StartInfo.FileName = pathToApp;
p.EnableRaisingEvents = true;
p.Exited += OnCalibrationProcessExited;  // hooks up your handler to the Process
p.Start();

// Now .NET will call this method when the process exits
private void OnCalibrationProcessExited(object sender, EventArgs e)
{
  // set Topmost
}
从comments线程中,将在工作线程上引发退出事件,因此您需要使用Dispatcher.BeginInvoke切换到UI线程以设置最顶层:

private void OnCalibrationProcessExited(object sender, EventArgs e)
{
  Action action = () => { /* set Topmost */ };
  Dispatcher.BeginInvoke(DispatcherPriority.Normal, action);
}
(这假设代码在窗口类中。如果不是,则需要编写类似于
Application.Current.MainWindow.Dispatcher.BeginInvoke(…)
的代码。)


注意:我已将创建和配置Process对象与启动它分开。尽管这更为详细,但必须确保在流程开始之前,所有事件处理的内容都已准备就绪——否则流程可能会在您将处理程序放置到位之前退出(不太可能,但理论上可能!),并且您的处理程序将永远不会被调用。

您可以通过以下方式等待流程退出:

如果您想提供一个超时值以防止进程永远等待,也可以这样做。例如,如果您想等待最多2分钟,可以执行以下操作:

process.WaitForExit(2 * 60000); // 60000ms/minute

您可以通过以下方式等待进程退出:

如果您想提供一个超时值以防止进程永远等待,也可以这样做。例如,如果您想等待最多2分钟,可以执行以下操作:

process.WaitForExit(2 * 60000); // 60000ms/minute

似乎更容易只是等待过程,因为他想要“模态”行为。更容易,但对用户来说可能更糟糕。如果用户按Alt+键返回到主窗口怎么办?如果校准过程中出现问题,其窗口消失,但过程不退出,该怎么办?用户被甩回应用程序,但应用程序完全冻结,甚至不会响应关闭按钮。这是一种折衷,但对我来说,少量的额外代码是值得的。我尝试了这一点,但得到了以下错误:System.InvalidOperationException:调用线程无法访问此对象,因为另一个线程拥有它。在System.Windows.Threading.Dispatcher.VerifyAccess()中,这就是我在倒数第二段中提到的跨线程问题。我会更新答案。似乎更容易只是等待过程,因为他想要“模态”行为。更容易,但对用户来说可能更糟糕。如果用户按Alt+键返回到主窗口怎么办?如果校准过程中出现问题,其窗口消失,但过程不退出,该怎么办?用户被甩回应用程序,但应用程序完全冻结,甚至不会响应关闭按钮。这是一种折衷,但对我来说,少量的额外代码是值得的。我尝试了这一点,但得到了以下错误:System.InvalidOperationException:调用线程无法访问此对象,因为另一个线程拥有它。在System.Windows.Threading.Dispatcher.VerifyAccess()中,这就是我在倒数第二段中提到的跨线程问题。我会更新答案。