In meiner WPF-Anwendung muss beim Start eine schnelle Routine ausgeführt werden, die nach einer neuen verfügbaren Version sucht. Wenn die Version verfügbar ist, führen wir das Update durch und möchten dann die App sofort neu starten. Da dies ausgeführt wird, bevor das Hauptfenster für den Benutzer angezeigt wird, scheint es einfach so, als ob die Anwendung eine Sekunde länger zum Starten benötigt.Starten Sie die WPF-Anwendung vom Nicht-UI-Thread aus
Wir verwenden Squirrel.Windows für unseren Updater. Ich habe die unten stehende Klasse zur Überprüfung/Anwendung von Updates eingerichtet.
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();
}
}
}
}
Leider Eichhörnchen haben ihren Aktualisierungsprozess async
nur vorgenommen, was bedeutet, das CheckForUpdate
und UpdateApp
Verfahren await
verwenden müssen, die gesamten Aktualisierungsverfahren asynchron zu machen. Ich ordne den asnyc-Aufruf einer Task
, dann einfach .Wait()
für das Update zu beenden.
Das Problem kommt, wenn ich versuche, meine App neu zu starten. Basierend auf dem, was ich gelesen habe, muss ich Dispatcher.Invoke
verwenden, um den Neustart aufgrund der Tatsache, dass ich in einem Nicht-UI-Thread bei der Durchführung des Updates bin. Doch trotz des Code unten, ich immer noch die gleiche Fehlermeldung:
Der Aufruf Thread dieses Objekt nicht, weil ein anderer Thread besitzt es zugreifen kann
Jede Idee, wie richtig Dispatcher.Invoke
implementieren, um die App neu starten?
// Instantiate new UpdateVersion object passing in the URL
UpdateVersion updateVersion = new UpdateVersion(System.Configuration.ConfigurationManager.AppSettings.Get("SquirrelDirectory"));
// Assign Dispatch.Invoke as Restart action delegate
updateVersion.Restart +=() =>
{
Dispatcher.Invoke(() =>
{
Process.Start(ResourceAssembly.Location);
Current.Shutdown();
});
};
// This is here for debugging purposes so I know the update is occurring
updateVersion.Progress += (count) =>
{
Debug.WriteLine($"Progress.. {count}");
};
var task = Task.Run(async() => { await updateVersion.UpdateVersions(); });
task.Wait();
EDIT
Unten finden Sie einen Screenshot des Target
Attribut des Restart
Aktion. Der Debugger wurde in der Zeile Restar?.Invoke
von oben angehalten.
Wo ist der Code ausgeführt wird, ist es in Ihrem Programm. cs oder eine 'Application' Veranstaltung? – CodingGorilla
Keine Program.cs-Datei es ist die OnStartup-Methode der Anwendung. Dies ist der erste Befehl, den das Programm ausführt. – NealR
Sie könnten in Betracht ziehen, '' Program.cs' 'mit einer 'Main'-Methode (zB einer Konsolen-App) zu ergänzen, diese als Startobjekt (unter Eigenschaften -> Anwendung) festzulegen und dann von dort aus zu aktualisieren. Auf diese Weise können Sie einfach wählen, das Hauptfenster nicht zu starten, wenn ein Update durchgeführt werden muss. – CodingGorilla