Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Dans cette étape, demandez à l’assistant les parties nonvisuelles de l’application. En gardant cette modification distincte du code XAML, les erreurs du compilateur et les problèmes de conception sont plus faciles à isoler.
Demander un modèle et un service de stockage
Ignorez cette invite :
Add the data layer for TaskTally.
- Create a TaskItem model with an ID, title, and completion state.
- Use MVVM Toolkit observable properties.
- Create a TaskStorage service that serializes the task list to JSON.
- Store tasks in ApplicationData.Current.LocalFolder because this is
a packaged WinUI 3 app.
- Return an empty list when the file doesn't exist.
- Serialize save operations so rapid changes don't write the file concurrently.
- Surface real read and write errors to the caller.
- Build the project after the change.
Comparez le modèle généré avec cette implémentation :
using CommunityToolkit.Mvvm.ComponentModel;
namespace TaskTally.Models;
public partial class TaskItem : ObservableObject
{
public Guid Id { get; init; } = Guid.NewGuid();
[ObservableProperty]
public partial string Title { get; set; } = string.Empty;
[ObservableProperty]
public partial bool IsComplete { get; set; }
}
L’attribut [ObservableProperty] génère des propriétés publiques et des notifications de modification. La classe doit être partial telle que le générateur source du kit de ressources MVVM peut ajouter ce code.
Le service de stockage doit ressembler à ceci :
using System.Text.Json;
using System.Threading;
using TaskTally.Models;
using Windows.Storage;
namespace TaskTally.Services;
internal static class TaskStorage
{
private const string FileName = "tasks.json";
private static readonly SemaphoreSlim SaveLock = new(1, 1);
public static async Task<IReadOnlyList<TaskItem>> LoadAsync()
{
StorageFile? file =
await ApplicationData.Current.LocalFolder.TryGetItemAsync(FileName) as StorageFile;
if (file is null)
{
return [];
}
string json = await FileIO.ReadTextAsync(file);
return JsonSerializer.Deserialize<List<TaskItem>>(json) ?? [];
}
public static async Task SaveAsync(IEnumerable<TaskItem> tasks)
{
await SaveLock.WaitAsync();
try
{
string json = JsonSerializer.Serialize(tasks, new JsonSerializerOptions
{
WriteIndented = true
});
StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(
FileName,
CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(file, json);
}
finally
{
SaveLock.Release();
}
}
}
ApplicationData.Current.LocalFolder est approprié ici, car l’application a une identité de package.
SaveLock empêche les opérations d’ajout, de suppression et d’achèvement d’écrire simultanément le même fichier. Si vous modifiez ultérieurement le modèle de distribution, vérifiez à nouveau l’hypothèse de l’identité du package au lieu de copier automatiquement ce choix de stockage.
En savoir plus : Stocker et récupérer des paramètres et d’autres données d’application et ApplicationData.LocalFolder.
Demander le modèle d’affichage
Utilisez ensuite cette invite :
Add MainPageViewModel.
- Expose an ObservableCollection<TaskItem>.
- Add observable properties for the new-task text and status message.
- Add asynchronous commands to add and delete tasks.
- Disable AddTaskCommand when the title is blank.
- Load tasks once when the page starts.
- Save after add, delete, or completion changes.
- Expose a summary and empty-state property for x:Bind.
- Catch storage exceptions only where the UI can report them.
- Build and fix all warnings.
Les principaux modèles à inspecter dans la réponse sont les suivants :
public ObservableCollection<TaskItem> Tasks { get; } = [];
[ObservableProperty]
public partial string NewTaskTitle { get; set; } = string.Empty;
public string Summary =>
Tasks.Count == 0
? "No tasks yet"
: $"{Tasks.Count(task => !task.IsComplete)} of {Tasks.Count} remaining";
[RelayCommand(CanExecute = nameof(CanAddTask))]
private async Task AddTaskAsync()
{
string title = NewTaskTitle.Trim();
Tasks.Add(new TaskItem { Title = title });
NewTaskTitle = string.Empty;
RefreshTaskState();
await SaveAsync($"Added \"{title}\".");
}
[RelayCommand]
private async Task DeleteTaskAsync(TaskItem task)
{
Tasks.Remove(task);
RefreshTaskState();
await SaveAsync($"Deleted \"{task.Title}\".");
}
private bool CanAddTask() => !string.IsNullOrWhiteSpace(NewTaskTitle);
partial void OnNewTaskTitleChanged(string value)
{
AddTaskCommand.NotifyCanExecuteChanged();
}
Vérifiez que l’Assistant ne bloque pas le travail asynchrone avec .Wait() ou .Result. Les opérations de stockage doivent être attendues.
Le modèle d’affichage peut intercepter les exceptions de stockage lorsqu’il les convertit en message pour la page :
private async Task SaveAsync(string successMessage)
{
try
{
await TaskStorage.SaveAsync(Tasks);
ShowStatus(successMessage);
}
catch (Exception ex)
{
ShowStatus($"Changes couldn't be saved: {ex.Message}");
}
}
Ce n’est pas un secours silencieux : l’utilisateur reçoit une erreur et le modèle d’affichage ne prétend pas que l’enregistrement a réussi.
Créer et inspecter
Compiler pour x64. Traitez les avertissements comme des éléments de travail, en particulier ceux relatifs aux liaisons et à la nullabilité des références :
dotnet build -p:Platform=x64
Demandez à l’assistant d’expliquer chaque package ajouté. Pour cette application, aucun nouveau package ne doit être nécessaire au-delà des références SDK d'application Windows et MVVM Toolkit dans le modèle.
Windows developer