Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Nesta etapa, peça ao assistente as partes não visuais do aplicativo. Manter essa alteração separada do XAML torna os erros do compilador e os problemas de design mais fáceis de isolar.
Solicitar um modelo e um serviço de armazenamento
Utilize este comando:
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.
Compare o modelo gerado com esta implementação:
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; }
}
O [ObservableProperty] atributo gera propriedades públicas e altera as notificações. A classe deve ser partial para que o gerador de origem do Kit de Ferramentas MVVM possa adicionar esse código.
O serviço de armazenamento deve ter esta aparência:
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 é apropriado aqui porque o aplicativo tem a identidade do pacote.
SaveLock impede que as operações de adição, exclusão e conclusão gravem o mesmo arquivo simultaneamente. Se você alterar posteriormente o modelo de distribuição, verifique a suposição de identidade do pacote novamente em vez de copiar essa opção de armazenamento automaticamente.
Saiba mais: Armazene e recupere configurações e outros dados do aplicativo e ApplicationData.LocalFolder.
Solicitar o modelo de exibição
Em seguida, use este prompt:
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.
Os principais padrões a serem inspecionados na resposta são:
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();
}
Verifique se o assistente não bloqueia o trabalho assíncrono com .Wait() ou .Result. As operações de armazenamento devem ser aguardadas.
O modelo de exibição pode capturar exceções de armazenamento quando as converte em uma mensagem para a página:
private async Task SaveAsync(string successMessage)
{
try
{
await TaskStorage.SaveAsync(Tasks);
ShowStatus(successMessage);
}
catch (Exception ex)
{
ShowStatus($"Changes couldn't be saved: {ex.Message}");
}
}
Esse não é um fallback silencioso: o usuário recebe um erro e o modelo de exibição não afirma que o salvamento foi bem-sucedido.
Compilar e inspecionar
Compilar para x64. Trate os avisos como itens de trabalho, especialmente avisos de associação e referência anulável:
dotnet build -p:Platform=x64
Peça ao assistente para explicar todos os pacotes adicionados. Para este aplicativo, nenhum novo pacote deve ser necessário além das referências do SDK do Aplicativo Windows e do Kit de Ferramentas MVVM no modelo.
Windows developer