次に、アシスタントにページの作成を依頼します。 別の UI フレームワークのコントロールに置き換えないように、必要な WinUI コントロールに名前を付けます。
XAML を要求する
次のプロンプトを使います。
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.
生成された XAML でこれらの詳細を調べます。
データ入力
<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" />
表示 Header は、入力がその唯一のラベルとしてプレースホルダー テキストに依存しないことを意味します。
UpdateSourceTrigger=PropertyChanged は、ユーザーが入力したビュー モデルを更新するため、コマンドをすぐに有効にすることができます。
タスク一覧
型指定されたデータ テンプレートを定義します。
<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>
静的関数を使用して、タスク タイトルを削除ボタンのオートメーション名に含め、スクリーン リーダーで行を区別できるようにします。
public static string DeleteTaskName(string title) => $"Delete {title}";
次に、コレクションをバインドします。
<ListView
AutomationProperties.Name="Tasks"
ItemTemplate="{StaticResource TaskTemplate}"
ItemsSource="{x:Bind ViewModel.Tasks, Mode=OneWay}"
SelectionMode="None" />
ListView では、スクロールと UI の仮想化が提供されます。
ScrollViewerでラップすると、両方に干渉します。
詳細情報: XAML を使用 した ListView と GridView と データ バインディング。
状態と空状態
非ブロッキング 状態メッセージには、 InfoBar を使用します。
<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}" />
コンバーター クラスを追加せずに空の状態のブール値を Visibility に変換するには、静的関数を使用します。
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}" />
データを追加する前にアプリを実行し、空の状態がクリアされ 、[タスクの追加 ] ボタンが無効になっていることを確認します。
アダプティブ レイアウト
表示状態を使用して、入力の下にボタンを移動します。
<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>
ブレークポイント全体で実行中のアプリのサイズを変更します。 プロンプトの応答性の高い要求は、レイアウトが機能することを示す証拠ではありません。
詳細情報: XAML を使用したレスポンシブ レイアウト。
ビュー固有のイベントを接続する
このページは、永続化されたデータを 1 回読み込み、タスクの変更をビュー モデルに委任します。
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);
}
}
}
XAML イベントにはvoidが必要なため、ここではasync void戻り値の型を持つイベント ハンドラーが適しています。 アプリ内の他の非同期メソッドは、 Taskを返します。
ビルドと実行
アプリをビルドし、そのパッケージを使用して起動し、現在実装されているすべての受け入れ条件をテストします。
- マウスでタスクを追加します。
- キーボードのみを使用してタスクを追加します。
- タスクを完了して削除します。
- アプリを閉じて再起動し、永続化を確認します。
- 有効な 640 ピクセル以下のウィンドウのサイズを変更します。
- 明るいテーマ、濃色テーマ、コントラスト テーマを切り替えます。
Windows developer