Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从非UI线程重新启动WPF应用程序_C#_Wpf_Multithreading_Dispatcher - Fatal编程技术网

C# 从非UI线程重新启动WPF应用程序

C# 从非UI线程重新启动WPF应用程序,c#,wpf,multithreading,dispatcher,C#,Wpf,Multithreading,Dispatcher,在我的WPF应用程序中,我需要在启动时运行一个快速例程,检查新的可用版本。如果版本可用,我们将进行更新,然后立即重新启动应用程序。因为这是在用户看到主窗口之前运行的,所以它看起来就像应用程序启动需要一秒钟的时间 我们正在使用更新程序。我创建了下面的类来处理检查/应用更新 public class UpdateVersion { private readonly UpdateManager _updateManager; public Action<int> Prog

在我的WPF应用程序中,我需要在启动时运行一个快速例程,检查新的可用版本。如果版本可用,我们将进行更新,然后立即重新启动应用程序。因为这是在用户看到主窗口之前运行的,所以它看起来就像应用程序启动需要一秒钟的时间

我们正在使用更新程序。我创建了下面的类来处理检查/应用更新

public class UpdateVersion
{
    private readonly UpdateManager _updateManager;

    public Action<int> Progress;
    public event Action Restart;
    public UpdateVersion(string squirrelUrl)
    {
        _updateManager = new UpdateManager(squirrelUrl);
    }

    public async Task UpdateVersions()
    {
        using (_updateManager)
        {
            UpdateInfo updateInfo = await _updateManager.CheckForUpdate(progress:Progress);
            if (updateInfo.CurrentlyInstalledVersion == null)
            {
                if (updateInfo.FutureReleaseEntry != null)
                {
                    await _updateManager.UpdateApp(Progress);

                    // Job crashes here
                    Restart?.Invoke();
                }
            }
            else if (updateInfo.CurrentlyInstalledVersion.Version < updateInfo.FutureReleaseEntry.Version)
            {
                await _updateManager.UpdateApp(Progress);

                // Job crashes here
                Restart?.Invoke();
            }
        }
    }
}
编辑

下面是
重启
操作的
目标
属性的屏幕截图。调试器在
Restar?.Invoke
行上暂停


因此,实际异常在
重新启动
处理程序中的某个位置,该处理程序正试图基于堆栈跟踪从另一个线程访问
main窗口
get属性。这是一个完全的猜测,但我会将原始的
调度程序
存储在
OnStartup
方法中,并在
重新启动
事件处理程序中使用存储的调度程序。

为什么不使用
SplashScreen
?此
SplashScreen
将检查新版本,并下载更新或启动旧应用程序


这是一个很好的入门教程:

与其尝试将异步编程转换为旧的基于事件的模式,不如正确地使用它。您不需要事件来检测异步操作何时完成,也不需要
Invoke
返回UI线程<代码>等待同时处理这两个问题

您可以编写如下简单的代码:

static readonly SemanticVersion ZeroVersion = new SemanticVersion(0, 0, 0, 0);


private async void Application_Startup(object sender, StartupEventArgs e)
{
    await CheckForUpdatesAsync();
}

private async Task CheckForUpdatesAsync()
{
    string squirrelUrl = "...";


    var updateProgress = new Progress<int>();
    IProgress<int> progress = updateProgress;

    //Create a splash screen that binds to progress and show it
    var splash = new UpdateSplash(updateProgress);
    splash.Show();

    using (var updateManager = new UpdateManager(squirrelUrl))
    {

        //IProgress<int>.Report matches Action<i>
        var info = await updateManager.CheckForUpdate(progress: progress.Report);

        //Get the current and future versions. 
        //If missing, replace them with version Zero
        var currentVersion = info.CurrentlyInstalledVersion?.Version ?? ZeroVersion;
        var futureVersion = info.FutureReleaseEntry?.Version ?? ZeroVersion;

        //Is there a newer version?
        if (currentVersion < futureVersion)
        {
            await updateManager.UpdateApp(progress.Report);
            Restart();
        }
    }
    splash.Hide();
}

private void Restart()
{
    Process.Start(ResourceAssembly.Location);
    Current.Shutdown();
}
static readonly SemanticVersion ZeroVersion=新的SemanticVersion(0,0,0,0);
私有异步无效应用程序\u启动(对象发送方、StartupEventArgs e)
{
等待CheckForUpdatesAsync();
}
私有异步任务CheckForUpdatesAsync()
{
字符串squirreURL=“…”;
var updateProgress=新进度();
IProgress progress=updateProgress;
//创建一个绑定到progress的启动屏幕并显示它
var splash=newupdatesplash(updateProgress);
splash.Show();
使用(var updateManager=newupdatemanager(squirrelUrl))
{
//IProgress。报告匹配操作
var info=await updateManager.CheckForUpdate(进度:progress.Report);
//获取当前和将来的版本。
//如果丢失,请将其替换为零版
var currentVersion=info.currentlysinstalledVersion?.Version??零版本;
var futureVersion=信息。FutureReleaseEntry?.Version??零版本;
//有更新的版本吗?
如果(当前版本<未来版本)
{
等待updateManager.UpdateApp(progress.Report);
重启();
}
}
splash.Hide();
}
私有void Restart()
{
进程启动(ResourceAssembly.Location);
当前关闭();
}
这刚好足够将代码提取到一个单独的类:

private async void Application_Startup(object sender, StartupEventArgs e)
{
        var updater = new Updater();
        await updater.CheckForUpdatesAsync(...);
}

// ...

class Updater
{
    static readonly SemanticVersion ZeroVersion = new SemanticVersion(0, 0, 0, 0);


    public async Task CheckForUpdatesAsync(string squirrelUrl)
    {
        var updateProgress = new Progress<int>();
        IProgress<int> progress = updateProgress;

        //Create a splash screen that binds to progress and show it
        var splash = new UpdateSplash(updateProgress);
        splash.Show();

        using (var updateManager = new UpdateManager(squirrelUrl))
        {

            var updateInfo = await updateManager.CheckForUpdate(progress: progress.Report);

            //Get the current and future versions. If missing, replace them with version Zero
            var currentVersion = updateInfo.CurrentlyInstalledVersion?.Version ?? ZeroVersion;
            var futureVersion = updateInfo.FutureReleaseEntry?.Version ?? ZeroVersion;

            //Is there a newer version?
            if (currentVersion < futureVersion)
            {
                await updateManager.UpdateApp(progress.Report);
                Restart();
            }
        }
        splash.Hide();
    }

    private void Restart()
    {
        Process.Start(Application.ResourceAssembly.Location);
        Application.Current.Shutdown();
    }
}
private async void应用程序\u启动(对象发送方,StartupEventArgs e)
{
var updater=new updater();
等待更新程序。检查更新同步(…);
}
// ...
类更新程序
{
静态只读SemanticVersion ZeroVersion=新SemanticVersion(0,0,0,0);
公共异步任务CheckForUpdatesAsync(字符串URL)
{
var updateProgress=新进度();
IProgress progress=updateProgress;
//创建一个绑定到progress的启动屏幕并显示它
var splash=newupdatesplash(updateProgress);
splash.Show();
使用(var updateManager=newupdatemanager(squirrelUrl))
{
var updateInfo=await updateManager.CheckForUpdate(进度:progress.Report);
//获取当前和未来版本。如果缺少,请将其替换为零版本
var currentVersion=updateInfo.CurrentlyInstalledVersion?.Version??ZeroVersion;
var futureVersion=updateInfo.FutureReleaseEntry?.Version??零版本;
//有更新的版本吗?
如果(当前版本<未来版本)
{
等待updateManager.UpdateApp(progress.Report);
重启();
}
}
splash.Hide();
}
私有void Restart()
{
Process.Start(Application.resourcepassembly.Location);
Application.Current.Shutdown();
}
}

代码在哪里运行,是在Program.cs中还是在
应用程序
事件中?没有Program.cs文件这是应用程序的
启动
方法。这是程序运行的第一个命令。您可以考虑添加<代码>程序。CS < /代码>使用<代码>主< /COD>方法(如控制台应用程序),将其设置为启动对象(在属性->应用程序下),然后从那里进行更新。这样,当需要进行更新时,您只需选择不启动主窗口。不幸的是,此时无法更改启动过程。根据您在此处显示的代码和您的注释,即代码是在
OnStartup()
方法中执行的,我预计程序会死锁,而不是抛出异常。事实上,当我试图重现这个问题时,这正是发生的情况(即僵局)。请提供一份可靠地再现问题的良好报告。请注意,当您使用第三方库时,似乎没有任何问题本身与此相关;您应该能够通过模拟库的操作来重现问题。
private async void Application_Startup(object sender, StartupEventArgs e)
{
        var updater = new Updater();
        await updater.CheckForUpdatesAsync(...);
}

// ...

class Updater
{
    static readonly SemanticVersion ZeroVersion = new SemanticVersion(0, 0, 0, 0);


    public async Task CheckForUpdatesAsync(string squirrelUrl)
    {
        var updateProgress = new Progress<int>();
        IProgress<int> progress = updateProgress;

        //Create a splash screen that binds to progress and show it
        var splash = new UpdateSplash(updateProgress);
        splash.Show();

        using (var updateManager = new UpdateManager(squirrelUrl))
        {

            var updateInfo = await updateManager.CheckForUpdate(progress: progress.Report);

            //Get the current and future versions. If missing, replace them with version Zero
            var currentVersion = updateInfo.CurrentlyInstalledVersion?.Version ?? ZeroVersion;
            var futureVersion = updateInfo.FutureReleaseEntry?.Version ?? ZeroVersion;

            //Is there a newer version?
            if (currentVersion < futureVersion)
            {
                await updateManager.UpdateApp(progress.Report);
                Restart();
            }
        }
        splash.Hide();
    }

    private void Restart()
    {
        Process.Start(Application.ResourceAssembly.Location);
        Application.Current.Shutdown();
    }
}