Skip to Content
Week 06Day 3 - 常用控件

Day 3 - 常用控件

建议用时:210-240 分钟

你将学会什么

  • 知道 TextBlockTextBoxButtonCheckBoxComboBoxListBox 分别负责什么。
  • 会写控件最常用的属性:TextContentPlaceholderTextIsCheckedSelectedIndexClick
  • 会用 x:Name 给控件命名,让 C# 代码能找到它。
  • 会写一个按钮点击事件,从输入框、复选框、下拉框里读取值。
  • 会把读取到的数据显示到界面上,而不是只让按钮摆在那里。

本页先用 code-behind 写点击事件,也就是在 MainWindow.axaml.cs 里处理按钮点击。这样最直接,能看清“界面控件”和“C# 代码”是怎么连接的。后面再学习 MVVM 和命令绑定。

本页固定顺序

  1. 先学第一部分:弄懂今天最小、最重要的知识,并运行短例子。
  2. 再学第二部分:把刚学的知识组合成一个完整例子。
  3. 然后做第三部分:自己跟着敲,再完成重复训练和每日小测。
  4. 最后做第四部分:先独立完成作业,再用完整答案检查。

学习衔接

上一页学习的是“XAML 布局”,今天继续学习“常用控件”。先使用上一页已经会的写法,再只增加今天这个新知识点;如果前置内容还不能独立敲出,先回上一页复习,不要硬跳。

今天的最低通过线

第一次学习不要求背完整页。完成下面 3 项,就可以继续:

  • 能用自己的话说明“常用控件”解决什么问题。
  • 把第一部分的短例子亲手敲完,并确认每个例子都能运行。
  • 不看完整答案完成第三部分至少前 3 个例子,再主动改一个值观察结果。

第一部分:先学原理和最小知识

这一部分从最小知识开始。先读解释,再把紧跟着的短例子敲一遍。今天不追求控件数量多,而是把“显示、输入、点击、选择、反馈”这一条链路搞清楚。

1. 控件是什么

控件就是窗口上能看见或能操作的界面元素。

控件作用常见位置
TextBlock显示只读文字标题、标签、提示
TextBox输入或显示一段文本名称、价格、备注
Button触发一个动作保存、删除、查询
CheckBox表示是或否是否启用、是否默认
ComboBox从多个选项里选一个分类、状态、类型
ListBox显示一组条目商品列表、菜单、日志

先按“用户要看什么、输入什么、点击什么、选择什么”来选控件。

2. TextBlockTextBox 不一样

TextBlock 用来显示文字,用户一般不能直接改。

<TextBlock Text="商品名称" />

TextBox 用来输入文字,用户可以点进去打字。

<TextBox Text="Keyboard" />

不要用 TextBox 充当普通说明文字。说明文字用 TextBlock,输入内容才用 TextBox

3. ContentText 的区别

Avalonia 控件常见两个属性:TextContent

属性常见控件含义
TextTextBlockTextBox文字内容
ContentButtonCheckBoxListBoxItemComboBoxItem控件里面显示的内容

例子:

<TextBlock Text="商品名称" /> <Button Content="保存" />

按钮用 Content,因为按钮里面将来不一定只能放文字,也可以放更复杂的内容。

4. PlaceholderText 是输入提示,不是真正输入值

<TextBox PlaceholderText="请输入商品名称" />

PlaceholderText 只是输入框为空时显示的提示。用户没有输入时,TextBox.Text 不会自动变成 请输入商品名称

如果要给输入框一个真实默认值,要写:

<TextBox Text="Keyboard" />

5. x:Name 的作用

如果 C# 代码要读取某个控件,就要先让这个控件有名字。

<TextBox x:Name="NameBox" />

有了这个名字,MainWindow.axaml.cs 里就能写:

string name = NameBox.Text ?? "";

名字要清楚,推荐用“含义 + 控件类型”的方式:

控件用途推荐名字
商品名称输入框NameBox
分类下拉框CategoryBox
是否启用复选框EnabledBox
结果文字ResultText

6. Button 的 Click 事件

按钮本身只是一个控件。它不会自动保存数据。要让按钮做事,需要把点击事件连接到 C# 方法。

XAML 里写:

<Button Content="保存" Click="OnSaveClick" />

C# 里写:

private void OnSaveClick(object? sender, RoutedEventArgs e) { ResultText.Text = "已经点击保存。"; }

Click="OnSaveClick" 的意思是:用户点击按钮时,执行名叫 OnSaveClick 的方法。

7. 事件方法的两个参数是什么

private void OnSaveClick(object? sender, RoutedEventArgs e)

先理解到这个程度就够:

参数含义
sender触发事件的那个控件,一般就是按钮
e事件附带的信息

普通按钮点击里经常用不到这两个参数,但方法签名要写对,否则 XAML 找不到对应方法。

8. CheckBox.IsChecked 为什么要写 == true

CheckBox.IsChecked 的类型不是普通 bool,它可以是:

  • true:选中。
  • false:没选中。
  • null:不确定状态。

所以常见写法是:

bool enabled = EnabledBox.IsChecked == true;

这句话的意思是:只有明确等于 true,才当成启用。

9. ComboBox.SelectedItem 读出来是什么

如果你的下拉框里写的是 ComboBoxItem

<ComboBox x:Name="CategoryBox"> <ComboBoxItem Content="普通商品" /> <ComboBoxItem Content="虚拟商品" /> </ComboBox>

那么 C# 里读 SelectedItem 时,拿到的是被选中的 ComboBoxItem

string category = CategoryBox.SelectedItem is ComboBoxItem item ? item.Content?.ToString() ?? "未选择分类" : "未选择分类";

这段代码做了两件事:

  1. 确认选中的东西确实是 ComboBoxItem
  2. item.Content 里取出真正显示的文字。

10. 控件值读取顺序

写点击事件时,不要一上来就写很多逻辑。按这个顺序:

  1. 先读取输入框。
  2. 再读取复选框。
  3. 再读取下拉框。
  4. 再拼出一段结果文字。
  5. 最后把结果显示到 TextBlock

也就是:输入控件 -> C# 方法 -> 输出控件。

Avalonia 常用控件属性速查

控件常用属性作用
TextBlockText显示文字
TextBoxTextPlaceholderText输入文本和提示
ButtonContentClickCommand按钮文字和操作
CheckBoxIsCheckedContent勾选状态
ComboBoxItemsSourceSelectedItem下拉选择
ListBoxItemsSourceSelectedItem列表和选中项
BorderPaddingMarginBorderThickness包裹内容
DatePickerSelectedDate日期选择

输入框最常用写法:

<TextBox Text="{Binding ProductName, Mode=TwoWay}" PlaceholderText="请输入商品名称" />

按钮最常用写法:

<Button Content="保存" Command="{Binding SaveCommand}" />

第二部分:把知识组合成完整例子

今天要做的是一个“商品录入小窗口”。窗口里有输入框、复选框、下拉框、列表和按钮。点击按钮后,C# 代码会读取控件上的值,再把结果显示到页面底部。

MainWindow.axaml

把下面内容放到 Views/MainWindow.axaml

<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ProductApp.Views.MainWindow" Width="640" Height="460" Title="常用控件练习"> <Grid RowDefinitions="Auto,Auto,Auto,*" RowSpacing="12" Margin="20"> <TextBlock Grid.Row="0" Text="商品录入" FontSize="24" FontWeight="Bold" /> <Grid Grid.Row="1" RowDefinitions="Auto,Auto,Auto" ColumnDefinitions="Auto,*" RowSpacing="10" ColumnSpacing="12"> <TextBlock Grid.Row="0" Grid.Column="0" Text="名称" VerticalAlignment="Center" /> <TextBox x:Name="NameBox" Grid.Row="0" Grid.Column="1" PlaceholderText="请输入商品名称" Text="Keyboard" /> <TextBlock Grid.Row="1" Grid.Column="0" Text="分类" VerticalAlignment="Center" /> <ComboBox x:Name="CategoryBox" Grid.Row="1" Grid.Column="1" SelectedIndex="0"> <ComboBoxItem Content="普通商品" /> <ComboBoxItem Content="虚拟商品" /> <ComboBoxItem Content="服务商品" /> </ComboBox> <TextBlock Grid.Row="2" Grid.Column="0" Text="状态" VerticalAlignment="Center" /> <CheckBox x:Name="EnabledBox" Grid.Row="2" Grid.Column="1" Content="启用这个商品" IsChecked="True" /> </Grid> <StackPanel Grid.Row="2" Orientation="Horizontal" Spacing="8"> <Button Content="保存" Click="OnSaveClick" /> <Button Content="清空结果" Click="OnClearClick" /> </StackPanel> <Border Grid.Row="3" BorderBrush="#DDDDDD" BorderThickness="1" Padding="12"> <StackPanel Spacing="8"> <TextBlock Text="当前商品列表" FontWeight="Bold" /> <ListBox> <ListBoxItem Content="Keyboard" /> <ListBoxItem Content="Mouse" /> <ListBoxItem Content="Monitor" /> </ListBox> <TextBlock x:Name="ResultText" Text="点击保存后,这里会显示读取到的数据。" /> </StackPanel> </Border> </Grid> </Window>

MainWindow.axaml.cs

把下面内容放到 Views/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 ?? ""; bool enabled = EnabledBox.IsChecked == true; string category = CategoryBox.SelectedItem is ComboBoxItem item ? item.Content?.ToString() ?? "未选择分类" : "未选择分类"; ResultText.Text = $"名称:{name};分类:{category};启用:{enabled}"; } private void OnClearClick(object? sender, RoutedEventArgs e) { ResultText.Text = "结果已清空。"; } }

先用一句话理解

XAML 负责把控件画出来;x:Name 给控件起名字;Click="OnSaveClick" 把按钮和 C# 方法连接起来;C# 方法读取控件值并修改 ResultText.Text

第三部分:跟着敲代码

从这里开始动手。每个例子都说明要改哪个文件。先运行窗口,再改下一段。

例子 1:只显示控件,不写事件

先练控件本身。把下面内容放到 Views/MainWindow.axaml

<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ProductApp.Views.MainWindow" Width="460" Height="360" Title="控件显示"> <StackPanel Margin="20" Spacing="10"> <TextBlock Text="商品名称" FontSize="18" FontWeight="Bold" /> <TextBox PlaceholderText="请输入商品名称" /> <CheckBox Content="启用这个商品" IsChecked="True" /> <ComboBox SelectedIndex="0"> <ComboBoxItem Content="普通商品" /> <ComboBoxItem Content="虚拟商品" /> <ComboBoxItem Content="服务商品" /> </ComboBox> <Button Content="保存" /> <ListBox> <ListBoxItem Content="Keyboard" /> <ListBoxItem Content="Mouse" /> <ListBoxItem Content="Monitor" /> </ListBox> </StackPanel> </Window>

运行后先确认:

  • 能看到输入框。
  • 能勾选和取消勾选复选框。
  • 能展开下拉框。
  • 能看到列表。
  • 按钮能被点击,但现在不会执行保存逻辑。

例子 2:按钮点击后修改文字

这个例子先不读取输入,只练“按钮 -> C# 方法 -> 修改界面文字”。

MainWindow.axaml

<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ProductApp.Views.MainWindow" Width="420" Height="240" Title="按钮点击"> <StackPanel Margin="20" Spacing="12"> <Button Content="点我" Click="OnButtonClick" /> <TextBlock x:Name="MessageText" Text="按钮还没有被点击。" /> </StackPanel> </Window>

MainWindow.axaml.cs

using Avalonia.Controls; using Avalonia.Interactivity; namespace ProductApp.Views; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void OnButtonClick(object? sender, RoutedEventArgs e) { MessageText.Text = "按钮已经被点击。"; } }

这一步只看一件事:Click="OnButtonClick" 和 C# 里的 OnButtonClick 名字必须完全一致。

例子 3:点击按钮读取 TextBox

这个例子开始读取输入框里的文字。

MainWindow.axaml

<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ProductApp.Views.MainWindow" Width="460" Height="260" Title="读取 TextBox"> <StackPanel Margin="20" Spacing="10"> <TextBlock Text="商品名称" /> <TextBox x:Name="NameBox" PlaceholderText="请输入商品名称" /> <Button Content="显示名称" Click="OnShowNameClick" /> <TextBlock x:Name="ResultText" Text="这里会显示输入结果。" /> </StackPanel> </Window>

MainWindow.axaml.cs

using Avalonia.Controls; using Avalonia.Interactivity; namespace ProductApp.Views; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void OnShowNameClick(object? sender, RoutedEventArgs e) { string name = NameBox.Text ?? ""; ResultText.Text = $"你输入的商品名称是:{name}"; } }

如果输入框是空的,NameBox.Text 可能是 null?? "" 的意思是:如果没有文字,就当成空字符串处理。

例子 4:读取 CheckBox 的选中状态

MainWindow.axaml

<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ProductApp.Views.MainWindow" Width="460" Height="240" Title="读取 CheckBox"> <StackPanel Margin="20" Spacing="12"> <CheckBox x:Name="EnabledBox" Content="启用这个商品" IsChecked="True" /> <Button Content="读取状态" Click="OnReadEnabledClick" /> <TextBlock x:Name="ResultText" Text="这里会显示启用状态。" /> </StackPanel> </Window>

MainWindow.axaml.cs

using Avalonia.Controls; using Avalonia.Interactivity; namespace ProductApp.Views; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void OnReadEnabledClick(object? sender, RoutedEventArgs e) { bool enabled = EnabledBox.IsChecked == true; ResultText.Text = enabled ? "当前状态:启用" : "当前状态:停用"; } }

这里不要直接写 bool enabled = EnabledBox.IsChecked;,因为 IsChecked 不是普通 bool

例子 5:读取 ComboBox 的选中项

MainWindow.axaml

<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ProductApp.Views.MainWindow" Width="480" Height="260" Title="读取 ComboBox"> <StackPanel Margin="20" Spacing="12"> <TextBlock Text="商品分类" /> <ComboBox x:Name="CategoryBox" SelectedIndex="0"> <ComboBoxItem Content="普通商品" /> <ComboBoxItem Content="虚拟商品" /> <ComboBoxItem Content="服务商品" /> </ComboBox> <Button Content="读取分类" Click="OnReadCategoryClick" /> <TextBlock x:Name="ResultText" Text="这里会显示选中的分类。" /> </StackPanel> </Window>

MainWindow.axaml.cs

using Avalonia.Controls; using Avalonia.Interactivity; namespace ProductApp.Views; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void OnReadCategoryClick(object? sender, RoutedEventArgs e) { string category = CategoryBox.SelectedItem is ComboBoxItem item ? item.Content?.ToString() ?? "未选择分类" : "未选择分类"; ResultText.Text = $"当前分类:{category}"; } }

这段写法看起来长,但它解决了两个问题:没有选中时不会报错,选中后能拿到真正显示的文字。

例子 6:组合成一个商品录入表单

这个例子把前面的控件组合到一个表单里。

MainWindow.axaml

<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ProductApp.Views.MainWindow" Width="620" Height="420" Title="商品录入"> <Grid RowDefinitions="Auto,Auto,*" RowSpacing="12" Margin="20"> <TextBlock Grid.Row="0" Text="商品录入" FontSize="24" FontWeight="Bold" /> <Grid Grid.Row="1" RowDefinitions="Auto,Auto,Auto,Auto" ColumnDefinitions="Auto,*" RowSpacing="10" ColumnSpacing="12"> <TextBlock Grid.Row="0" Grid.Column="0" Text="名称" VerticalAlignment="Center" /> <TextBox x:Name="NameBox" Grid.Row="0" Grid.Column="1" PlaceholderText="请输入商品名称" /> <TextBlock Grid.Row="1" Grid.Column="0" Text="分类" VerticalAlignment="Center" /> <ComboBox x:Name="CategoryBox" Grid.Row="1" Grid.Column="1" SelectedIndex="0"> <ComboBoxItem Content="普通商品" /> <ComboBoxItem Content="虚拟商品" /> <ComboBoxItem Content="服务商品" /> </ComboBox> <TextBlock Grid.Row="2" Grid.Column="0" Text="状态" VerticalAlignment="Center" /> <CheckBox x:Name="EnabledBox" Grid.Row="2" Grid.Column="1" Content="启用商品" IsChecked="True" /> <Button Grid.Row="3" Grid.Column="1" Content="保存" HorizontalAlignment="Right" Click="OnSaveClick" /> </Grid> <TextBlock x:Name="ResultText" Grid.Row="2" Text="保存结果会显示在这里。" /> </Grid> </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 ?? ""; bool enabled = EnabledBox.IsChecked == true; string category = CategoryBox.SelectedItem is ComboBoxItem item ? item.Content?.ToString() ?? "未选择分类" : "未选择分类"; ResultText.Text = $"保存成功:{name}{category},启用状态:{enabled}"; } }

常见错误和修法

错误为什么错修法
控件名字没写code-behind 找不到控件需要在 C# 访问时加 x:Name
TextBox.Text 可能为空输入框内容不一定有值读取后先做空白判断
ComboBox 没有默认选项保存时可能没有选中值设置 SelectedIndex 或处理空值
按钮点击事件名写错XAML 找不到处理方法XAML 和 .axaml.cs 方法名保持一致
错误提示没有固定位置用户不知道哪里出错页面保留 ErrorTextMessageText

小白重复敲写训练

控件不要一次放满窗口,每段只练三种。

训练 1:文本输入和按钮

<StackPanel Margin="20" Spacing="8"> <TextBox Name="NameInput" Watermark="请输入名称" /> <Button Content="读取名称" Click="ReadName_Click" /> <TextBlock Name="ResultText" /> </StackPanel>
private void ReadName_Click(object? sender, RoutedEventArgs e) { ResultText.Text = NameInput.Text; }

训练 2:复选框

<CheckBox Name="EnabledCheck" Content="启用商品" /> <Button Content="检查" Click="Check_Click" />
private void Check_Click(object? sender, RoutedEventArgs e) { ResultText.Text = EnabledCheck.IsChecked == true ? "已启用" : "未启用"; }

训练 3:下拉选择

<ComboBox Name="CategoryBox" SelectedIndex="0"> <ComboBoxItem Content="电脑" /> <ComboBoxItem Content="配件" /> <ComboBoxItem Content="办公" /> </ComboBox>

第三遍增加一个分类,并尝试读取当前选择。

每日小测

做完本页后,用这 5 题检查是否真的掌握。

1. 判断题

本页的目标不是只把代码运行起来,还要能说清楚“为什么这样写”。

答案:对。能运行只是第一步,能解释原理、常用操作和常见错误,才说明本页内容进入了可复用能力。

2. 填空题

本页主题是:常用控件。今天至少要掌握的 3 个点是:

1. 知道 `TextBlock`、`TextBox`、`Button`、`CheckBox`、`ComboBox`、`ListBox` 分别负责什么。 2. 会写控件最常用的属性:`Text`、`Content`、`PlaceholderText`、`IsChecked`、`SelectedIndex`、`Click`。 3. 会用 `x:Name` 给控件命名,让 C# 代码能找到它。

答案:以上 3 点必须能用自己的代码跑通,不能只停留在阅读。

3. 流程题

遇到本页相关功能时,先按什么顺序处理?

答案:先看完整例子,确认最终效果;再读原理和名词;然后跟着第三部分从空项目敲代码;最后对照作业答案检查。

4. 找错误题

如果本页代码运行失败,第一步应该做什么?

答案:先看终端或 IDE 里的第一条错误,找到文件名和行号;不要同时改很多地方。再回到本页的“常见错误和修法”表格,对照错误类型逐项排查。

5. 改需求题

在本页完整例子跑通后,至少改一个小需求。

可选改法:

  • 改一个字段名称。
  • 多加一个校验条件。
  • 多输出一行结果。
  • 把固定数据改成用户输入。
  • 把一次处理改成多条数据处理。

答案标准:修改后能重新运行,并能说明这次修改影响了哪一段逻辑。重点检查:知道 TextBlock、TextBox、Button、CheckBox、ComboBox、ListBox 分别负责什么。。

上位机专项练习

TextBox、ComboBox、Button、CheckBox 和 DataGrid 是配置与监控界面的常用控件。

下面 3 个例子都要亲手敲。先运行原代码,再完成每个例子后面的改动任务。

专项例子 1:填写设备连接参数

<StackPanel Margin="20" Spacing="10"> <TextBox Watermark="设备名称" Text="PLC-01" /> <ComboBox SelectedIndex="0"> <ComboBoxItem Content="Modbus TCP" /> <ComboBoxItem Content="Modbus RTU" /> </ComboBox> <CheckBox Content="启动时自动连接" /> <Button Content="保存配置" /> </StackPanel>

运行结果或界面效果:

可以输入名称、选择协议和保存

改动任务: 增加 IP 地址输入框。

专项例子 2:显示实时数值

<StackPanel Margin="20"> <TextBlock Text="当前温度" /> <TextBlock Text="26.8 C" FontSize="36" FontWeight="Bold" /> <ProgressBar Minimum="0" Maximum="100" Value="26.8" /> </StackPanel>

运行结果或界面效果:

文字和进度条同时显示温度

改动任务: 把最大值改成 80。

专项例子 3:显示设备表格

<DataGrid AutoGenerateColumns="False" Height="220"> <DataGrid.Columns> <DataGridTextColumn Header="设备" Binding="{Binding Name}" /> <DataGridTextColumn Header="状态" Binding="{Binding Status}" /> <DataGridTextColumn Header="温度" Binding="{Binding Temperature}" /> </DataGrid.Columns> </DataGrid>

运行结果或界面效果:

表格包含设备、状态、温度三列

改动任务: 增加“更新时间”列。

第四部分:作业完整答案

这一部分给出当天作业的完整答案。先照第三部分敲一遍,再用这里检查结果。

作业要求

做一个静态商品录入窗口,并且按钮点击后能读取控件值。

页面必须包含:

  1. TextBox:输入商品名称。
  2. ComboBox:选择商品分类。
  3. CheckBox:选择是否启用。
  4. ListBox:显示已有商品。
  5. Button:点击后读取上面三个输入控件。
  6. TextBlock:显示保存结果。

拆解步骤

  1. 先在 MainWindow.axaml 里把控件摆出来。
  2. 给 C# 代码要读取的控件加 x:Name
  3. 给按钮加 Click="OnSaveClick"
  4. MainWindow.axaml.cs 里写 OnSaveClick 方法。
  5. 在方法里读取 NameBox.Text
  6. 在方法里读取 EnabledBox.IsChecked == true
  7. 在方法里读取 CategoryBox.SelectedItem
  8. 最后把结果写到 ResultText.Text

MainWindow.axaml 完整答案

<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ProductApp.Views.MainWindow" Width="640" Height="460" Title="常用控件练习"> <Grid RowDefinitions="Auto,Auto,Auto,*" RowSpacing="12" Margin="20"> <TextBlock Grid.Row="0" Text="商品录入" FontSize="24" FontWeight="Bold" /> <Grid Grid.Row="1" RowDefinitions="Auto,Auto,Auto" ColumnDefinitions="Auto,*" RowSpacing="10" ColumnSpacing="12"> <TextBlock Grid.Row="0" Grid.Column="0" Text="名称" VerticalAlignment="Center" /> <TextBox x:Name="NameBox" Grid.Row="0" Grid.Column="1" PlaceholderText="请输入商品名称" Text="Keyboard" /> <TextBlock Grid.Row="1" Grid.Column="0" Text="分类" VerticalAlignment="Center" /> <ComboBox x:Name="CategoryBox" Grid.Row="1" Grid.Column="1" SelectedIndex="0"> <ComboBoxItem Content="普通商品" /> <ComboBoxItem Content="虚拟商品" /> <ComboBoxItem Content="服务商品" /> </ComboBox> <TextBlock Grid.Row="2" Grid.Column="0" Text="状态" VerticalAlignment="Center" /> <CheckBox x:Name="EnabledBox" Grid.Row="2" Grid.Column="1" Content="启用这个商品" IsChecked="True" /> </Grid> <StackPanel Grid.Row="2" Orientation="Horizontal" Spacing="8"> <Button Content="保存" Click="OnSaveClick" /> <Button Content="清空结果" Click="OnClearClick" /> </StackPanel> <Border Grid.Row="3" BorderBrush="#DDDDDD" BorderThickness="1" Padding="12"> <StackPanel Spacing="8"> <TextBlock Text="当前商品列表" FontWeight="Bold" /> <ListBox> <ListBoxItem Content="Keyboard" /> <ListBoxItem Content="Mouse" /> <ListBoxItem Content="Monitor" /> </ListBox> <TextBlock x:Name="ResultText" Text="点击保存后,这里会显示读取到的数据。" /> </StackPanel> </Border> </Grid> </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 ?? ""; bool enabled = EnabledBox.IsChecked == true; string category = CategoryBox.SelectedItem is ComboBoxItem item ? item.Content?.ToString() ?? "未选择分类" : "未选择分类"; ResultText.Text = $"名称:{name};分类:{category};启用:{enabled}"; } private void OnClearClick(object? sender, RoutedEventArgs e) { ResultText.Text = "结果已清空。"; } }

运行后应该看到什么

  • 页面顶部显示 商品录入
  • 输入框里默认有 Keyboard
  • 分类下拉框默认选中 普通商品
  • 复选框默认是选中状态。
  • 点击 保存 后,底部文字显示名称、分类和启用状态。
  • 点击 清空结果 后,底部文字变成 结果已清空。

如果报错,按这个顺序检查

  1. 如果提示找不到 OnSaveClick,检查 XAML 里的 Click 名字和 C# 方法名是否完全一致。
  2. 如果提示找不到 NameBox,检查 TextBox 是否写了 x:Name="NameBox"
  3. 如果提示找不到 RoutedEventArgs,检查 .axaml.cs 顶部是否有 using Avalonia.Interactivity;
  4. 如果点击按钮没有变化,检查 ResultText 这个 TextBlock 是否写了 x:Name="ResultText"
  5. 如果分类显示 未选择分类,检查 ComboBox 是否有 SelectedIndex="0"

今天真正要掌握的闭环

界面交互可以先按这条线理解:

用户输入或选择 -> 用户点击按钮 -> Click 事件执行 C# 方法 -> C# 方法读取控件值 -> C# 方法把结果写回界面

能把这条线走通,后面的绑定、命令、MVVM 才有落点。