如何重新启动WPF应用程序?

96

如何重新启动WPF应用程序?

在Windows Forms中,我使用以下代码:

System.Windows.Forms.Application.Restart();

那么在WPF中该怎么做呢?


4
可能有重复:https://dev59.com/y2865IYBdhLWcg3wSMcw,https://dev59.com/lkfYs4cB2Jgan1znCDa4,https://dev59.com/fFDTa4cB1Zd3GeqPHTu0。共识是没有完全重复 WinForms 方法的内容,所有“解决方案”都有点儿 hacky 的味道。我怀疑这是因为通常情况下不应该有这种需求,除了在调试期间。 - Cody Gray
现在我再次调用那些在应用程序启动时被调用的方法。它工作得很好。但对于其他应用程序,我必须重新启动应用程序。 - Hooch
3
@Cody Gray 为什么你说永远不需要这个?有很多原因可能需要重新启动应用程序,为什么要强制用户重新运行可执行文件,当你可以为他们完成呢? - epalm
1
@epalm:就是这样:我想不出一个应用程序需要重新启动的理由,除了在调试期间。也许如果你已经自动下载和安装更新,但这应该使用单独的更新程序完成,应该只在启动/关闭时发生,并且应该让用户决定是否要继续在应用程序中工作(例如Firefox和Chrome)。 - Cody Gray
4
@ Cody Gray - 这是一个例子(除非你能给我更好的方法来完成这个任务)。我们正在运行一个使用WPF连接服务器的应用程序。它发现服务器,然后使用该发现信息编写客户端配置。在下载配置后,该应用程序无法立即使用该信息,需要重启应用程序。请问还有其他更好的方法吗? - Dirk Dastardly
@Drew,或者你可以重新加载ConfigurationManager - Tom Padilla
8个回答

124

我找到了这个: 它可以工作。 但是, 是否有更好的方法?

System.Diagnostics.Process.Start(Application.ResourceAssembly.Location);
Application.Current.Shutdown();

1
@AndreiRinea 不需要。只需在开始时保存它们,并将它们作为参数传递给此函数调用即可。很容易。 - Hooch
19
请注意,如果您的应用程序使用ClickOnce部署,不建议使用此方法。当您重新启动时,ApplicationDeployment.IsNetworkDeployed将为false。有关更多信息,请参见http://bit.ly/RKoVBz。如果您的应用程序未使用ClickOnce部署,则此方法非常有效。 - blachniet
@blachniet,如果“ApplicationDeployment.IsNetworkDeployed”为false,那么对我的应用程序会有什么影响? - Mark
1
@ChristianMark,这可能没有影响。这取决于您的应用程序。我过去曾经开发过一些应用程序,既有ClickOnce部署,也有普通安装程序部署,其中一些部分根据ApplicationDeployment.IsNetworkDeployed是否为真而表现出不同的行为。例如,如果您在组织内进行ClickOnce部署,则可以推断您应该可以访问组织网络资源(文件共享、电子邮件服务器等)。 - blachniet
3
如果你想保留命令行参数,可以首先从Environment.GetCommandLineArgs()获取它们,然后将它们传递给Process.Start方法。 - Ahmed Fwela
显示剩余6条评论

48

我在 WPF 中使用过这个,成功了:

System.Windows.Forms.Application.Restart();
System.Windows.Application.Current.Shutdown();

7
仅仅为了这个目的而包含WinForms程序集引用,我认为有点过头了。 - Matěj Zábský
12
我倾向于同意,但是我已经在同一个项目中使用了类似于System.Windows.Forms.FolderBrowserDialog()这样的WinForms魔法。 - epalm
3
在使用 ClickOnce 时甚至是必要的。 - John
2
这是我找到的唯一重启ClickOnce应用程序的方法。谢谢。 - CamHart

19

在1秒的延迟后,通过命令行运行程序的新实例。 在此期间,当前实例将关闭。

ProcessStartInfo Info = new ProcessStartInfo();
Info.Arguments = "/C choice /C Y /N /D Y /T 1 & START \"\" \"" + Assembly.GetEntryAssembly().Location + "\"";
Info.WindowStyle = ProcessWindowStyle.Hidden;
Info.CreateNoWindow = true;
Info.FileName = "cmd.exe";
Process.Start(Info);
Process.GetCurrentProcess().Kill();

编辑:

我修复了代码:

将:Assembly.GetExecutingAssembly().Location

替换为:Assembly.GetEntryAssembly().Location

当函数在单独的DLL中运行时,这一点非常重要。

并且 -

将:Application.Current.Shutdown();

替换为:Process.GetCurrentProcess().Kill();

它将在WinForms和WPF中都起作用,如果您编写了一个既适用于WinForms又适用于WPF的dll,则这一点非常重要。


谢谢,完美运作 <3 - undefined

16
Application.Current.Shutdown();
System.Windows.Forms.Application.Restart();

这个顺序适用于我,反过来做只会启动应用程序的另一个实例。


2
我不能告诉你为什么它在WPF中有效,但只能告诉你它确实有效。 - Jraco11
在WinForms中对我来说完美运作! - A. Zalonis
刚刚在我的 .NET 4.8 WPF 应用程序上尝试了一下,完美运行。=] - Paul Karkoska

12
Application.Restart();
或者
System.Diagnostics.Process.Start(Application.ExecutablePath);
Application.Exit();

我的程序中有一个互斥对象,用来确保在计算机上只有一个应用程序实例在运行。由于互斥对象没有及时释放,导致新启动的应用程序不能启动。因此,在 Properties.Settings 中放置了一个值,表示应用程序正在重新启动。在调用 Application.Restart() 之前,将 Properties.Settings 值设置为 true。在 Program.Main() 中,我还添加了对该特定属性设置值的检查,以便在值为 true 时将其重置为 false,并进行 Thread.Sleep(3000)。

你的程序中可能有以下逻辑:

if (ShouldRestartApp)
{
   Properties.Settings.Default.IsRestarting = true;
   Properties.Settings.Default.Save();
   Application.Restart();
}

在 Program.Main() 中

[STAThread]
static void Main()
{
   Mutex runOnce = null;

   if (Properties.Settings.Default.IsRestarting)
   {
      Properties.Settings.Default.IsRestarting = false;
      Properties.Settings.Default.Save();
      Thread.Sleep(3000);
   }

   try
   {
      runOnce = new Mutex(true, "SOME_MUTEX_NAME");

      if (runOnce.WaitOne(TimeSpan.Zero))
      {
         Application.EnableVisualStyles();
         Application.SetCompatibleTextRenderingDefault(false);
         Application.Run(new Form1());
      }
   }
   finally
   {
      if (null != runOnce)
         runOnce.Close();
   }
}

就是这样。


20
这个被标记为答案的回答是误导性的。原问题是关于如何重新启动一个WPF应用程序,类似于在WinForms中所做的方式。不幸的是,你的回答仍然使用了WinForms的重新启动方法(这在WPF中不可用),并且还包含一些与问题无关的例子(比如Mutex?)。 - test-in-prod
7
可能对于仅限于WPF的回答有误导性,但结合其他答案使用对我很有用,因为我需要重新启动使用互斥量的WPF。这个方法可以完成任务。 - Sebastien GISSINGER
忘掉使用WinForms的问题,绕过互斥锁最简单的方法难道不是在启动新实例之前释放它吗?任何依赖于Thread.Sleep来工作的东西可能都需要重新考虑。 - Jamie

5
这些提议的解决方案可能是可行的,但正如另一位评论者所提到的那样,它们感觉有点像快速 hack。另一种更为简洁的做法是运行一个批处理文件,其中包含延迟(例如 5 秒),以等待当前(正在关闭的)应用程序终止。
这可以防止两个应用程序实例同时打开。在我的情况下,同一时间打开两个应用程序实例是无效的——我使用了互斥体来确保只有一个应用程序处于打开状态——因为应用程序正在使用某些硬件资源。
示例 Windows 批处理文件("restart.bat"):
sleep 5
start "" "C:\Dev\MyApplication.exe"

在WPF应用程序中,添加以下代码:
// Launch the restart batch file
Process.Start(@"C:\Dev\restart.bat");

// Close the current application
Application.Current.MainWindow.Close();

12
编写带有延迟的批处理文件感觉像是一种冗长的黑客操作,可能更糟。 - Philliproso
@Philliproso同意,这是一种hack方法,在当时我需要一个完全新的Windows进程来重新启动应用程序,而其他方法在这里提供的我认为都不行,但这个方法可以。 - dodgy_coder
或者在启动新实例之前先释放互斥锁。 - Jamie

3
 Application.Restart();
 Process.GetCurrentProcess().Kill();

对我来说运行得很好


1
这对我很有帮助,避免了一个简单的问题,我的启动参数。在尝试任何重新启动方法时,我的应用程序都会崩溃,而这个方法可以让事情更安全。谢谢 :) - JustADev
7
你从哪里得到“重新启动”的?System.Windows.Application没有Restart方法。 - usefulBee

1
采用Hooch的例子,我使用了以下内容:
using System.Runtime.CompilerServices;

private void RestartMyApp([CallerMemberName] string callerName = "")
{
    Application.Current.Exit += (s, e) =>
    {
        const string allowedCallingMethod = "ButtonBase_OnClick"; // todo: Set your calling method here

        if (callerName == allowedCallingMethod)
        {
            Process.Start(Application.ResourceAssembly.Location);
        }
     };

     Application.Current.Shutdown(); // Environment.Exit(0); would also suffice 
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接