Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Bitten Sie nun den Assistenten, die Seite zu erstellen. Benennen Sie die gewünschten WinUI-Steuerelemente, damit es kein Steuerelement aus einem anderen Benutzeroberflächenframework ersetzt.
Bitten Sie um den XAML-Code
Verwenden Sie diese Eingabeaufforderung:
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.
Überprüfen Sie diese Details im generierten XAML.
Dateneingabe
<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" />
Das Sichtbare Header bedeutet, dass die Eingabe nicht auf Platzhaltertext als einzige Beschriftung angewiesen ist.
UpdateSourceTrigger=PropertyChanged aktualisiert das Ansichtsmodell während der Benutzereingabe, sodass der Befehl sofort aktiviert werden kann.
Aufgabensammlung
Definieren Sie eine typisierte Datenvorlage:
<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>
Verwenden Sie eine statische Funktion, um den Aufgabentitel in den Automatisierungsnamen der Löschschaltfläche einzuschließen, damit eine Bildschirmsprachausgabe zwischen Zeilen unterscheiden kann:
public static string DeleteTaskName(string title) => $"Delete {title}";
Binden Sie dann die Sammlung:
<ListView
AutomationProperties.Name="Tasks"
ItemTemplate="{StaticResource TaskTemplate}"
ItemsSource="{x:Bind ViewModel.Tasks, Mode=OneWay}"
SelectionMode="None" />
ListView stellt Bildlauf und UI-Virtualisierung bereit. Das Einbetten in ein ScrollViewer beeinträchtigt beide.
Weitere Informationen: ListView und GridView undDatenbindung mit XAML.
Status und leerer Zustand
Verwenden Sie InfoBar für eine nicht blockierende Statusmeldung:
<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}" />
Verwenden Sie eine statische Funktion, um den booleschen Visibility Zustand in einen leeren Zustand zu konvertieren, ohne eine Konverterklasse hinzuzufügen:
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}" />
Führen Sie die App vor dem Hinzufügen von Daten aus, und vergewissern Sie sich, dass der leere Zustand gelöscht ist, und die Schaltfläche " Aufgabe hinzufügen " ist deaktiviert:
Adaptives Layout
Verwenden Sie visuelle Zustände, um die Schaltfläche unter der Eingabe zu verschieben:
<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>
Ändern Sie die Größe der laufenden App über den Breakpoint hinweg. Die Behauptung in einem Prompt, dass das Layout responsiv ist, ist kein Beleg dafür, dass es tatsächlich funktioniert.
Weitere Informationen: Dynamische Layouts mit XAML.
Ansichtsspezifische Ereignisse verbinden
Die Seite lädt gespeicherte Daten einmal und delegiert Aufgabenänderungen an das Ansichtsmodell:
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);
}
}
}
Ereignishandler mit einem async void-Rückgabetyp sind hier angemessen, da XAML-Ereignisse void erfordern. Andere asynchrone Methoden in der App geben zurück Task.
Erstellen und Ausführen
Erstellen Sie die App, starten Sie sie über ihr Paket, und testen Sie jedes Akzeptanzkriterium, das jetzt implementiert wird:
- Fügen Sie eine Aufgabe mit der Maus hinzu.
- Fügen Sie eine Aufgabe nur über die Tastatur hinzu.
- Abschließen und Löschen einer Aufgabe.
- Schließen Sie die App, und starten Sie sie neu, um die Persistenz zu überprüfen.
- Ändern Sie die Größe des Fensters unter und über 640 effektiven Pixeln.
- Wechseln zwischen hellem, dunklem und kontrastreichem Design.
Windows developer