点击一次后更新WPF应用程序后如何重新启动(启动新版本)

23
如何在使用ClickOnce更新后重新启动WPF应用程序,我需要启动新版本!

更多上下文是什么?你是指自动化吗?还是远程?... - madd0
1
对于这种情况,请将“检查更新”配置在应用程序启动之前发生。这是发布选项中的一个选项。 - H H
@madd0:从代码中,使用 .Net 部署 API(即 Application.Deployment)安装 ClickOnce 更新后。 - Saw
@Henk Holterman: 但我已经在应用程序自身中开发了自定义部署,因此我不能依赖于应用程序启动前的自动更新。 - Saw
1
你尝试过在运行版本退出之前启动新版本的Process.Start吗? - madd0
6个回答

19

有几种方法,但大多数都无法正常工作,它们最终会重新打开旧版本。

听起来很疯狂,WPF没有正确处理它的方法 (#fixwpf),但您需要引用System.Windows.Forms.dll并调用System.Windows.Forms.Application.Restart();

快速搜索发现 Rob Relyea 在他的帖子中也提到了同样的问题 (XAML, WPF Microsoft Guy) http://robrelyea.wordpress.com/2007/07/24/application-restart-for-wpf/


16

为此而添加winforms程序集似乎有些过度,没有必要这样做。

在更新已应用之后,您可以执行与winforms在其重新启动方法背后执行的相同操作。

String ApplicationEntryPoint = ApplicationDeployment.CurrentDeployment.UpdatedApplicationFullName;

Process.Start(ApplicationEntryPoint);

//shutdown current instance here

这将使用适当的ClickOnce初始化开始您的应用程序的新版本。


3
由于某些原因,我必须使用 String ApplicationEntryPoint = ApplicationDeployment.CurrentDeployment.UpdateLocation.AbsoluteUri; - Carlos Blanco
1
只要您的默认浏览器支持ClickOnce部署,它就可以正常工作。在我的情况下,Chrome似乎无法正常工作,但仍然是一个很好的替代选择。 - reckface
Chrome似乎无法处理ClickOnce部署,它会显示一个保留/丢弃窗口。 - abhilash

3
        private static void RestartClickOnceApplication()
        {
            try
            {
                XDocument xDocument;
                using (MemoryStream memoryStream = new MemoryStream(AppDomain.CurrentDomain.ActivationContext.DeploymentManifestBytes))
                using (XmlTextReader xmlTextReader = new XmlTextReader(memoryStream))
                {
                    xDocument = XDocument.Load(xmlTextReader);
                }
                var description = xDocument.Root.Elements().Where(p => p.Name.LocalName == "description").First();
                var publisher = description.Attributes().Where(a => a.Name.LocalName == "publisher").First();
                var product = description.Attributes().Where(a => a.Name.LocalName == "product").First();

                var path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.StartMenu) + @"\Programs\";
                path += publisher.Value + @"\" + product.Value + ".appref-ms";

                if (File.Exists(path))
                {
                    Process.Start(path);
                    Application.Current.Shutdown();
                }
                else
                {
                    Application.Current.Shutdown();
                }
            }
            catch
            {
                Application.Current.Shutdown();
            }
        }

谢谢!我稍微修改了这个解决方案,使它对我起作用。var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Programs", publisher.Value, product.Value, product.Value + ".appref-ms"); - Витёк Синёв
@ВитёкСинёв 是的。Path.Combine更好。此代码中Where是不必要的,将其替换为First并删除末尾的First即可。description.Attributes().Where(a => a.Name.LocalName == "publisher").First(); - Erhan Urun

2
使用Michael提供的内容:
String ApplicationEntryPoint = ApplicationDeployment.CurrentDeployment.UpdatedApplicationFullName;

Process.Start(ApplicationEntryPoint);

确实存在浏览器无法正确处理的问题。例如,Edge在打开您的应用程序后会留下一个空白的浏览器页面。由于ApplicationDeployment.CurrentDeployment.UpdatedApplicationFullName指向一个很长的http网址,理论上也存在这样一种可能性,即在下载完成后的瞬间您的互联网断开连接,因此您的应用程序将无法重新启动(无法访问该网址)。

我选择了以下解决方案:

... Update()

if (System.IO.File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu) + "\\Programs\\MyCompany\\MyApp.appref-ms"))
{
   System.Diagnostics.Process.Start(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu) + "\\Programs\\MyCompany\\MyApp.appref-ms");
}
else if (System.IO.File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\MyApp.appref-ms"))
{
   System.Diagnostics.Process.Start(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\MyApp.appref-ms");
}
else throw new InvalidOperationException("Cannot restart the application, because StartMenu and Desktop shortcuts are missing!");

... shut down application (this.Close() etc.)

当然,这假定您已指定ClickOnce部署创建快捷方式,而且没有人删除它们的机会非常低。(如果没有这些快捷方式,用户可能无法执行您的应用程序,因为ClickOnce将.exe部署到一个非常深层的位置)。
如果您真的想这样做,您可以在最终的else语句中,而不是抛出异常,在临时目录中创建一个appref-ms文件(谷歌会帮助您),并执行它。

谢谢!你救了我的一天。 - GudarJS

1

一旦您启动了应用程序(即双击.application文件),您不会自动注意到,因为框架在启动时只会为您检查本地版本是否比应用程序下载站点中的版本旧。

但是,您可以使用ApplicationDeployment类来检查更新,它具有所有必要的手段。


0

在解决方案资源管理器中右键单击引用 > 单击添加引用 > 单击程序集 > 搜索并添加 System.Windows.Forms > 在 MainWindow 中添加 "System.Windows.Forms.Application.Restart();"。

完成!


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