Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Chiedere ora all'assistente di creare la pagina. Assegnare un nome ai controlli WinUI desiderati in modo da non sostituire un controllo da un altro framework dell'interfaccia utente.
Chiedere il codice XAML
Usare questa richiesta:
Create MainPage.xaml for TaskTally.
- Use a TextBox with a visible Header and an Add task Button.
- Use ListView for the task collection. Don't wrap it in ScrollViewer.
- In each row, use a CheckBox, task title, and delete Button.
- Use InfoBar for save and error status.
- Use x:Bind and specify Mode for every binding that changes.
- For TextBox.Text, use Mode=TwoWay and
UpdateSourceTrigger=PropertyChanged.
- Add accessible names and tooltips for icon-only commands.
- Add an empty state.
- At widths below 640 effective pixels, move the Add task button
below the TextBox and stretch it.
- Use theme resources instead of hard-coded colors.
- Build and fix all XAML compiler and analyzer warnings.
Esaminare questi dettagli nel codice XAML generato.
Immissione dati
<TextBox
x:Name="NewTaskTextBox"
Header="New task"
PlaceholderText="For example, review the generated XAML"
Text="{x:Bind ViewModel.NewTaskTitle, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
<Button
x:Name="AddTaskButton"
Grid.Column="1"
VerticalAlignment="Bottom"
AutomationProperties.Name="Add task"
Command="{x:Bind ViewModel.AddTaskCommand}"
Content="Add task" />
Il valore visibile Header indica che l'input non si basa sul testo segnaposto come unica etichetta.
UpdateSourceTrigger=PropertyChanged aggiorna il modello di visualizzazione mentre l'utente digita, in modo che il comando possa essere abilitato immediatamente.
Raccolta di attività
Definire un modello di dati tipizzato:
<DataTemplate x:Key="TaskTemplate" x:DataType="models:TaskItem">
<Grid Padding="8" ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CheckBox
VerticalAlignment="Center"
AutomationProperties.Name="{x:Bind Title}"
Click="TaskCheckBox_Click"
IsChecked="{x:Bind IsComplete, Mode=TwoWay}" />
<TextBlock
Grid.Column="1"
VerticalAlignment="Center"
Text="{x:Bind Title}" />
<Button
Grid.Column="2"
VerticalAlignment="Center"
AutomationProperties.Name="{x:Bind local:MainPage.DeleteTaskName(Title),
Mode=OneWay}"
Click="DeleteButton_Click"
DataContext="{x:Bind}"
ToolTipService.ToolTip="Delete task">
<FontIcon Glyph="" />
</Button>
</Grid>
</DataTemplate>
Utilizzare una funzione statica per includere il titolo dell'attività nel nome di automazione del pulsante Elimina, in modo che un lettore dello schermo possa distinguere le diverse righe:
public static string DeleteTaskName(string title) => $"Delete {title}";
Associare quindi la raccolta:
<ListView
AutomationProperties.Name="Tasks"
ItemTemplate="{StaticResource TaskTemplate}"
ItemsSource="{x:Bind ViewModel.Tasks, Mode=OneWay}"
SelectionMode="None" />
ListView fornisce lo scorrimento e la virtualizzazione dell'interfaccia utente. Avvolgerlo in un ScrollViewer interferisce con entrambi.
Altre informazioni: ListView e GridView eData binding con XAML.
Stato e stato vuoto
Usare InfoBar per un messaggio di stato non bloccante:
<InfoBar
IsClosable="True"
IsOpen="{x:Bind ViewModel.IsStatusOpen, Mode=TwoWay}"
Message="{x:Bind ViewModel.StatusMessage, Mode=OneWay}"
Severity="{x:Bind local:MainPage.StatusSeverity(ViewModel.HasError),
Mode=OneWay}" />
Usare una funzione statica per convertire il valore booleano vuoto in Visibility senza aggiungere una classe convertitore:
public static Visibility BoolToVisibility(bool value) =>
value ? Visibility.Visible : Visibility.Collapsed;
public static InfoBarSeverity StatusSeverity(bool hasError) =>
hasError ? InfoBarSeverity.Error : InfoBarSeverity.Success;
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="Add a task to get started."
Visibility="{x:Bind local:MainPage.BoolToVisibility(ViewModel.HasNoTasks),
Mode=OneWay}" />
Eseguire l'app prima di aggiungere dati e verificare che lo stato vuoto sia chiaro e che il pulsante Aggiungi attività sia disabilitato:
Layout adattivo
Usare gli stati di visualizzazione per spostare il pulsante sotto l'input:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="Narrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="AddTaskButton.(Grid.Row)" Value="1" />
<Setter Target="AddTaskButton.(Grid.Column)" Value="0" />
<Setter Target="AddTaskButton.HorizontalAlignment" Value="Stretch" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Standard">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="640" />
</VisualState.StateTriggers>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Ridimensiona l'app in esecuzione oltre il breakpoint. Un'affermazione sulla responsività nel prompt non dimostra che il layout funzioni.
Ulteriori informazioni: Layout adattivi con XAML.
Connettere eventi specifici della visualizzazione
La pagina carica i dati persistenti una volta e delega le modifiche dell'attività al modello di visualizzazione:
public sealed partial class MainPage : Page
{
public MainPageViewModel ViewModel { get; } = new();
public MainPage()
{
InitializeComponent();
Loaded += MainPage_Loaded;
}
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
Loaded -= MainPage_Loaded;
await ViewModel.InitializeAsync();
NewTaskTextBox.Focus(FocusState.Programmatic);
}
private async void TaskCheckBox_Click(object sender, RoutedEventArgs e)
{
await ViewModel.TaskCompletionChangedAsync();
}
private async void DeleteButton_Click(object sender, RoutedEventArgs e)
{
if (sender is Button { DataContext: TaskItem task })
{
await ViewModel.DeleteTaskCommand.ExecuteAsync(task);
}
}
}
I gestori di eventi con tipo restituito async void sono appropriati qui perché gli eventi XAML richiedono void. Altri metodi asincroni nell'app restituiscono Task.
Compilare ed eseguire
Compilare l'app, avviarla tramite il pacchetto e testare tutti i criteri di accettazione implementati:
- Aggiungere un'attività con il mouse.
- Aggiungere un'attività usando solo la tastiera.
- Completare ed eliminare un'attività.
- Chiudere e riavviare l'app per verificare la persistenza.
- Ridimensionare la finestra al di sotto e al di sopra di 640 pixel effettivi.
- Passare da un tema chiaro, scuro e a un tema a contrasto.