Skip to Content
Week 06📋 Week 06 阶段检查

Week 06 - 阶段检查

这一页用来确认 Week 6 是否已经变成可动手的能力。检查方式不是背概念,而是重新跑通三个窗口:布局窗口、按钮表单、列表详情。

本周学习地图

阶段先掌握什么最终能写什么
启动Avalonia 模板、Program.csApp.axaml能创建并运行窗口
布局GridStackPanelBorder能摆出清楚页面结构
控件TextBlockTextBoxButtonListBox能完成输入、点击、列表
表单读取控件值、校验、显示结果能写商品表单
列表列表、选中项、详情区域能做列表详情交互
过渡code-behind 到 MVVM能说明后面为什么要迁移

本周自测项目:Avalonia 商品窗口

从 Avalonia 模板开始写一个窗口,至少包含:

  • 商品名称、价格、库存输入框。
  • 保存按钮和清空按钮。
  • 错误提示和成功提示。
  • 商品列表。
  • 点击列表项后显示详情。

过关标准:能说清 MainWindow.axamlMainWindow.axaml.cs 分别负责什么。

上位机阶段验收:Avalonia 设备配置与监控窗口

本周目标: 从空 Avalonia 项目做出有布局、有控件、有交互的第一版桌面上位机。

必须亲手完成:

  1. 设备列表与详情左右分栏
  2. 设备名、IP、端口配置表单
  3. 开始、停止按钮和清晰状态反馈

过关标准: 窗口在桌面和较小尺寸下都能操作,输入错误有提示,按钮状态正确。

不要只看答案。新建一个空项目重做一次,运行成功后再故意改坏一处并自己排错。

本周流程图

Program.cs 启动应用 -> App.axaml 配置应用资源 -> MainWindow.axaml 描述窗口和控件 -> 用户输入 TextBox -> 用户点击 Button -> MainWindow.axaml.cs 读取控件值 -> 校验并更新 TextBlock 或 ListBox

第一部分:本周原理地图

Week 6 的主线是:把 C# 代码放进真实桌面窗口里,让用户能看见、输入、点击、选择,并看到处理结果。

本周能力拆解

能力你要能做到什么对应页面
创建项目能创建 Avalonia 项目并运行窗口Day 1
写布局能用 GridStackPanelBorder 摆区域Day 2
用控件能使用 TextBlockTextBoxButtonListBoxDay 3
管外观能用 ResourcesStyles 减少重复Day 4
写表单能读取输入、校验、显示错误和成功结果Day 5
做列表详情能选中列表项并显示、编辑当前项Day 6
做复盘能说清楚代码从用户操作到 C# 方法的流程Day 7

本周必须说清的 10 个关键词

关键词完整解释
Window一个桌面窗口,里面放布局和控件
XAML用来描述界面结构的标记语言
Grid按行列分配空间的布局容器
StackPanel按一个方向排列子控件的布局容器
Border包住一块内容,提供边框和内边距
TextBox接收用户文字输入的控件
Button.Click用户点击按钮后触发的事件
x:Name给控件起名字,让 C# 能访问它
ItemsSourceListBox 要显示的数据来源
SelectedItemListBox 当前选中的那一项

Week 6 必须会用的 Avalonia 写法

主题必须会的写法
项目运行dotnet new avalonia.mvvmdotnet rundotnet build
窗口WindowTitleWidthHeight
布局Grid RowDefinitionsColumnDefinitionsStackPanel Spacing
控件TextBlockTextBoxButtonListBoxComboBox
输入提示PlaceholderText
绑定文本Text="{Binding Name, Mode=TwoWay}"
命令按钮Command="{Binding SaveCommand}"
列表数据ItemsSource="{Binding Products}"
选中项SelectedItem="{Binding SelectedProduct}"
列表刷新ObservableCollection<T>
空状态IsVisible="{Binding IsEmpty}"
错误提示ErrorMessage 绑定到 TextBlock

本周最重要的数据流

用户看到窗口 -> 用户输入或选择 -> 用户点击按钮或切换列表项 -> Avalonia 执行 C# 事件方法 -> C# 读取控件值 -> C# 校验或修改数据 -> C# 把结果写回界面控件

如果这条线说不清,先回看 Day 3、Day 5、Day 6。

第二部分:阶段检查 1 - 布局窗口

目标:确认你能用 Grid 做出“顶部标题 + 左侧列表 + 右侧内容”的页面结构。

MainWindow.axaml 完整答案

<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ProductApp.Views.MainWindow" Width="700" Height="420" Title="布局检查"> <Grid RowDefinitions="Auto,*" ColumnDefinitions="220,*" RowSpacing="12" ColumnSpacing="16" Margin="20"> <TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Text="商品管理" FontSize="24" FontWeight="Bold" /> <Border Grid.Row="1" Grid.Column="0" BorderBrush="#DDDDDD" BorderThickness="1" Padding="12"> <StackPanel Spacing="8"> <TextBlock Text="左侧列表" FontWeight="Bold" /> <ListBox> <ListBoxItem Content="Keyboard" /> <ListBoxItem Content="Mouse" /> <ListBoxItem Content="Monitor" /> </ListBox> </StackPanel> </Border> <Border Grid.Row="1" Grid.Column="1" BorderBrush="#DDDDDD" BorderThickness="1" Padding="12"> <StackPanel Spacing="8"> <TextBlock Text="右侧详情" FontWeight="Bold" /> <TextBlock Text="这里以后显示当前商品详情。" /> </StackPanel> </Border> </Grid> </Window>

必须能解释

代码解释
RowDefinitions="Auto,*"第一行按标题高度,第二行占剩余高度
ColumnDefinitions="220,*"左侧固定 220,右侧占剩余宽度
Grid.ColumnSpan="2"标题横跨左右两列
Border Padding="12"边框和内部内容之间留空间

第三部分:阶段检查 2 - 按钮表单

目标:确认你能从 TextBox 读取输入,点击按钮后做校验,并显示结果。

MainWindow.axaml 完整答案

<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ProductApp.Views.MainWindow" Width="520" Height="320" Title="表单检查"> <StackPanel Margin="20" Spacing="10"> <TextBlock Text="商品名称" /> <TextBox x:Name="NameBox" PlaceholderText="请输入商品名称" /> <TextBlock Text="商品价格" /> <TextBox x:Name="PriceBox" PlaceholderText="请输入价格" /> <Button Content="保存" Click="OnSaveClick" /> <TextBlock x:Name="ResultText" Text="保存结果会显示在这里。" TextWrapping="Wrap" /> </StackPanel> </Window>

MainWindow.axaml.cs 完整答案

using Avalonia.Controls; using Avalonia.Interactivity; namespace ProductApp.Views; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void OnSaveClick(object? sender, RoutedEventArgs e) { string name = NameBox.Text?.Trim() ?? ""; if (name.Length == 0) { ResultText.Text = "商品名称不能为空。"; return; } string priceText = PriceBox.Text?.Trim() ?? ""; if (!decimal.TryParse(priceText, out decimal price)) { ResultText.Text = "价格必须是数字。"; return; } if (price <= 0) { ResultText.Text = "价格必须大于 0。"; return; } ResultText.Text = $"保存成功:{name},价格 {price}"; } }

必须验证的输入

名称价格应该显示
199商品名称不能为空。
Keyboardabc价格必须是数字。
Keyboard0价格必须大于 0。
Keyboard199保存成功:Keyboard,价格 199

第四部分:阶段检查 3 - 列表详情

目标:确认你能把一组 C# 对象显示到 ListBox,选中一项后显示详情。

MainWindow.axaml 完整答案

<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ProductApp.Views.MainWindow" Width="700" Height="420" Title="列表详情检查"> <Grid ColumnDefinitions="220,*" ColumnSpacing="16" Margin="20"> <ListBox x:Name="ProductList" Grid.Column="0" SelectionChanged="OnProductSelectionChanged" /> <StackPanel Grid.Column="1" Spacing="10"> <TextBlock Text="商品详情" FontSize="20" FontWeight="Bold" /> <TextBlock x:Name="NameText" Text="名称:" /> <TextBlock x:Name="PriceText" Text="价格:" /> <TextBlock x:Name="ResultText" Text="请选择左侧商品。" /> </StackPanel> </Grid> </Window>

MainWindow.axaml.cs 完整答案

using System.Collections.Generic; using Avalonia.Controls; namespace ProductApp.Views; public partial class MainWindow : Window { private readonly List<Product> _products = new() { new Product { Name = "Keyboard", Price = 199 }, new Product { Name = "Mouse", Price = 99 }, new Product { Name = "Monitor", Price = 899 } }; public MainWindow() { InitializeComponent(); ProductList.ItemsSource = _products; ProductList.SelectedIndex = 0; } private void OnProductSelectionChanged(object? sender, SelectionChangedEventArgs e) { Product? product = ProductList.SelectedItem as Product; if (product is null) { NameText.Text = "名称:"; PriceText.Text = "价格:"; ResultText.Text = "没有选中商品。"; return; } NameText.Text = $"名称:{product.Name}"; PriceText.Text = $"价格:{product.Price}"; ResultText.Text = $"当前选中:{product.Name}"; } private sealed class Product { public string Name { get; set; } = ""; public decimal Price { get; set; } public override string ToString() { return $"{Name} - {Price}"; } } }

必须能解释

代码解释
ProductList.ItemsSource = _products;让列表显示 C# 里的商品集合
ProductList.SelectedIndex = 0;启动后默认选中第一个商品
SelectionChanged="OnProductSelectionChanged"选中项变化时执行 C# 方法
ProductList.SelectedItem as Product把当前选中项转换成 Product
ToString()决定商品对象在列表里显示成什么文字

第五部分:常见错误完整修法

现象原因修法
XAML 报标签错误开始标签和结束标签不匹配从错误行往上找最近的 <Grid><StackPanel><Border>
C# 找不到 NameBoxXAML 控件没有 x:Namex:Name="NameBox"
C# 找不到 OnSaveClickXAML 的 Click 名字和 C# 方法名不同两边统一成 OnSaveClick
C# 找不到 RoutedEventArgs缺少事件命名空间using Avalonia.Interactivity;
列表显示类型名Product 没有重写 ToString()添加 public override string ToString()
输入字母导致价格处理失败直接转换数字使用 decimal.TryParse
没有选中商品时报错没判断 SelectedItem 是否为空先判断 product is null

第六部分:通过标准

达到下面标准,再进入 Week 7。

  1. 能创建并运行 Avalonia 项目。
  2. 能写出一个包含 Grid 的窗口。
  3. 能用 TextBox 输入数据。
  4. 能用 Button.Click 触发 C# 方法。
  5. 能用 x:Name 在 C# 中访问控件。
  6. 能用 decimal.TryParse 校验数字输入。
  7. 能把 C# 列表显示到 ListBox
  8. 能处理 SelectionChanged
  9. 能解释 ItemsSourceSelectedItem 的区别。
  10. 能根据第一条错误信息定位到文件和行号。

通过标准不是完全不犯错,而是能把错误缩小到具体文件、具体行、具体原因,并能把本周三个检查窗口重新跑通。