Efektivní správa stavu aplikace

V desktopové Windows App SDK aplikaci se váš proces bude spouštět, dokud ho uživatel explicitně nezavře. Desktopové aplikace neprocházejí automatickým pozastavením, obnovením a ukončením životního cyklu, který aplikace pro UPW používají. To vám dává větší kontrolu, ale také větší zodpovědnost za správu stavu.

Předpoklady

  • Desktopový projekt Windows App SDK. Postup nastavení najdete v tématu Vytvoření první aplikace WinUI 3.
  • Znalost třídy Microsoft.UI.Windowing.AppWindow a u balíčkovaných aplikací Windows.Storage.ApplicationData.

Important

Desktopové aplikace Windows App SDK se automaticky nepozastavují ani neobnovují, na rozdíl od aplikací UWP. Aplikace běží nepřetržitě, dokud ho uživatel nebo systém nevypíná. Stále byste měli implementovat dobré postupy správy stavu pro zpracování neočekávaných vypnutí, restartování systému a ztráty napájení.

Proč je správa států důležitá

I když operační systém neblokuje desktopové aplikace, stále existují situace, kdy vaše aplikace může ztratit neuložené stavy:

  • Uživatel zavře aplikaci, zatímco probíhá práce.
  • Systém se restartuje pro aktualizaci.
  • Ztráta napájení nebo zhroucení ukončí proces
  • Uživatel se odhlásí z Windows

Navrhněte aplikaci tak, aby tyto případy řádně zvládla uložením důležitého stavu a jeho obnovením při spuštění aplikace.

Uložit stav přírůstkově

Namísto ukládání veškerého stavu při vypnutí ukládejte stav průběžně během práce uživatele. To snižuje riziko ztráty dat a distribuuje náklady na vstupně-výstupní operace v průběhu životnosti vaší aplikace.

private async void OnThemeChanged(object sender, SelectionChangedEventArgs e)
{
    var selectedTheme = (sender as ComboBox)?.SelectedItem?.ToString();
    if (selectedTheme != null)
    {
        await SaveSettingAsync("AppTheme", selectedTheme);
    }
}

private async Task SaveSettingAsync(string key, string value)
{
    // Use local file storage, a database, or ApplicationData for packaged apps.
    var localFolder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
    var settingsDir = System.IO.Path.Combine(localFolder, "MyApp");
    Directory.CreateDirectory(settingsDir);
    var settingsPath = System.IO.Path.Combine(settingsDir, "settings.json");

    // Read existing settings, update, and save asynchronously.
    var settings = LoadSettings(settingsPath);
    settings[key] = value;
    await File.WriteAllTextAsync(settingsPath, System.Text.Json.JsonSerializer.Serialize(settings));
}

private Dictionary<string, string> LoadSettings(string path)
{
    // Read and deserialize the settings file, or return an empty set if it doesn't exist yet.
    if (!File.Exists(path))
    {
        return new Dictionary<string, string>();
    }

    var json = File.ReadAllText(path);
    return System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, string>>(json)
        ?? new Dictionary<string, string>();
}

Použijte ApplicationData pro balené aplikace

Pokud je vaše aplikace zabalená pomocí MSIX, můžete použít Windows.Storage.ApplicationData.Current.LocalSettings k ukládání malých nastavení a LocalFolder pro větší data. Tato umístění jsou spravována systémem a po odinstalaci aplikace se vyčistí.

Note

ApplicationData.Current vyžaduje identitu balíčku. Pokud vaše aplikace není zabalená, použijte místo toho Environment.SpecialFolder.LocalApplicationData nebo jiné standardní umístění souboru.

// For packaged apps with package identity:
string filePath = "C:\\Users\\Example\\Documents\\report.docx";
var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
localSettings.Values["LastOpenedFile"] = filePath;

Obnovení stavu při spuštění

Po spuštění aplikace zkontrolujte dříve uložený stav a obnovte ho. To uživateli poskytuje plynulý zážitek – pokračuje tam, kde skončil.

private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    // Restore the last opened file, if any.
    var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
    if (localSettings.Values.TryGetValue("LastOpenedFile", out var path))
    {
        OpenFile(path.ToString());
    }
}

private void OpenFile(string path)
{
    // Load the document at the given path and update the UI.
}

Zpracování události AppWindow.Closing

Použijte událost Closing na Microsoft.UI.Windowing.AppWindow k uložení kritického stavu před ukončením aplikace. Toto je vaše poslední příležitost zachovat stav, když uživatel okno zavře.

Important

Ve WinUI 3 událost Window.Closed nepodporuje zrušení. Chcete-li uživatele vyzvat před zavřením (například k uložení neuložených změn), použijte Microsoft.UI.Windowing.AppWindow.Closing místo toho událost, která poskytuje AppWindowClosingEventArgs objekt s Cancel vlastností.

// In your Window constructor or initialization code:
var appWindow = this.AppWindow;
appWindow.Closing += AppWindow_Closing;

void AppWindow_Closing(AppWindow sender, AppWindowClosingEventArgs args)
{
    // See the following examples for what to do here.
}
private void AppWindow_Closing(AppWindow sender, AppWindowClosingEventArgs args)
{
    SaveCurrentDocument();
    SaveWindowPosition();
}

private void SaveCurrentDocument()
{
    // Persist the current document to disk.
}

private void SaveWindowPosition()
{
    // Persist the window's current size and position.
}

Pokud chcete uživatele vyzvat před zavřením, nastavte args.Cancel = true , aby se okno nezavíralo, a potom ho po potvrzení uživatele programově zavřete. Použijte ochranný příznak, abyste zabránili opětovnému vstupu, protože volání this.Close() znovu vyvolá událost Closing:

private bool _isClosing = false;
private bool HasUnsavedChanges { get; set; }

private async void AppWindow_Closing(AppWindow sender, AppWindowClosingEventArgs args)
{
    if (_isClosing) return;

    if (HasUnsavedChanges)
    {
        args.Cancel = true; // Prevent the window from closing.

        // ShowSaveDialog returns true if the user chose to save.
        var shouldSave = await ShowSaveDialog();
        if (shouldSave)
        {
            await SaveCurrentDocumentAsync();
        }

        // Set the guard flag before closing to prevent re-entrancy.
        _isClosing = true;
        this.Close();
    }
}

private Task<bool> ShowSaveDialog()
{
    // Prompt the user to save, discard, or cancel.
    return Task.FromResult(true);
}

private Task SaveCurrentDocumentAsync()
{
    // Persist the current document to disk asynchronously.
    return Task.CompletedTask;
}

Osvědčené postupy

Practice Guidance
Časté ukládání Nečekejte na vypnutí – uložte stav, protože uživatel pracuje
Použití asynchronních vstupně-výstupních operací Použijte FileStream s useAsync: true nebo File.WriteAllTextAsync, abyste zabránili blokování uživatelského rozhraní
Minimalizovat velikost stavu Uložte jenom data, která potřebujete k obnovení pozice uživatele.
Zpracování událostí napájení Naslouchat na PowerManager.EnergySaverStatusChanged pro přizpůsobení chování
Testování neočekávaných vypnutí Ukončení aplikace a ověření obnovení stavu pomocí Správce úloh