用WPF做一个TianCat是什么体验

图片

项目规划

  • 前端:WPF/Vue

  • 后端:WebAPI

图片

项目体验

  • 注册和登录

图片

图片

  • 选择商品到购物车

图片

图片

  • 购物车结算

图片

项目成果

  • 目录

    图片

  • 小节1

01 · ItemsControl 列表控件

难度 ⭐⭐   |  应用页面 首页、商品列表、商品详情、购物车、下单、支付、订单列表、Dashboard 等 8+ 页面   |  代码出现 60+ 处


一、官方定义

ItemsControl 是 WPF 中最基础的集合控件——把一组数据(集合/数组)渲染成一组 UI 元素。

它本身只负责"遍历数据、逐个生成容器",不管数据怎么排列,也不管每个元素长什么样。排列方式交给 ItemsPanel元素外观交给 ItemTemplate

┌──────────────── ItemsControl ────────────────┐
│  ItemsSource  ←── ObservableCollection<T>     │
│  ItemsPanel    ←── 控制布局(横/竖/网格/换行) │
│  ItemTemplate  ←── 控制每个元素长什么样        │
└──────────────────────────────────────────────┘

一句话ItemsControl = 一个你可以完全控制布局外观的 for 循环。

和它的"亲戚"对比:

|
控件
|
特点
|
| — | — |
| ListBox |
ItemsControl + 选中高亮
|
| ListView |
ListBox + 列头排序
|
| DataGrid |
表格,自带行列结构
|
| ComboBox |
下拉选择
|

大多数场景下,ItemsControl 足够用,不需要上 ListBox/ListView。


二、项目实战

2.1 基础用法——商品分类导航(首页左侧黑底栏)

源码位置:Views/Fore/ForeHomeView.xaml:41-68

<ItemsControl ItemsSource="{Binding Categories}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Height="31"
                    Background="Transparent"
                    BorderThickness="0"
                    Command="{Binding DataContext.OpenCategoryCommand,
                              RelativeSource={RelativeSource AncestorType=UserControl}}"
                    CommandParameter="{Binding CategoryId}"
                    Cursor="Hand">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="42" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <Image Width="16" Height="16" Source="{Binding IconUri}" />
                    <TextBlock Grid.Column="1"
                               VerticalAlignment="Center"
                               Text="{Binding CategoryName}"
                               Foreground="White" FontSize="14" />
                </Grid>
            </Button>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

数据源(ViewModel):ObservableCollection<ForeCategoryFloor> Categories

// ViewModels/Fore/ForeHomeViewModel.cs
public ObservableCollection<ForeCategoryFloor> Categories { get; } = [];

// 从 API 获取数据
var data = await _catalogApiClient.HomeAsync();
foreach (var categoryElement in data.EnumerateArrayOrEmpty("categoryList"))
{
    Categories.Add(MapCategory(categoryElement));
}

关键点

  • ItemsSource="{Binding Categories}" —— 绑定集合,集合变化 UI 自动刷新

  • ItemTemplate 内的按钮通过 RelativeSource 找到父级 UserControl 上的 ViewModel 命令

  • 这里没有指定 ItemsPanel,默认是垂直 StackPanel


2.2 自定义布局——首页商品楼层(UniformGrid 4列排列)

源码位置:Views/Fore/ForeHomeView.xaml:92-130

<ItemsControl Grid.Column="1" ItemsSource="{Binding Products}">
    <!-- ★ 关键:用 ItemsPanelTemplate 自定义布局 -->
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <UniformGrid Columns="4" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Border Width="210" Height="286" Margin="13,0,0,16"
                    Background="White" BorderBrush="..." BorderThickness="1">
                <StackPanel>
                    <Image Width="165" Height="165"
                           Source="{Binding ImageUri}" ... />
                    <Button Command="..." CommandParameter="{Binding ProductId}">
                        <TextBlock Text="{Binding ProductName}" ... />
                    </Button>
                    <TextBlock Text="{Binding SalePrice, StringFormat=¥{0:F1}}"
                               Foreground="Red" FontSize="18" />
                </StackPanel>
            </Border>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

关键点

  • ItemsPanelTemplate 换成 UniformGrid  → 每行 4 列自适应

  • 每个商品卡是 210×286 的 Border,内有图片、名称、价格

  • StringFormat=¥{0:F1} 直接在 XAML 格式化价格显示


2.3 换行布局——商品列表页(WrapPanel)

源码位置:Views/Fore/ForeProductListView.xaml:108-229

<ItemsControl Margin="0,10,0,30" ItemsSource="{Binding Products}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <!-- 空数据 / 加载中 状态切换 -->
    <ItemsControl.Style>
        <Style TargetType="ItemsControl">
            <Setter Property="Visibility" Value="Visible" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding HasProducts}" Value="False">
                    <Setter Property="Visibility" Value="Collapsed" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ItemsControl.Style>
    ...
</ItemsControl>

三种布局对比(项目中实际使用的):

|
ItemsPanelTemplate
|
效果
|
使用场景
|
| — | — | — |
| StackPanel
(默认)
|
垂直堆叠
|
分类导航、订单列表、购物车
|
| UniformGrid Columns="4" |
固定列数网格
|
首页商品楼层(4列)
|
| WrapPanel |
自动换行流式
|
商品列表(窗口拉宽就多展示)
|
| StackPanel Orientation="Horizontal" |
水平排列
|
排序按钮栏、缩略图条
|


2.4 嵌套 ItemsControl——商品列表中的缩略图条

源码位置:Views/Fore/ForeProductListView.xaml:146-166

<!-- 外层 ItemsControl:遍历商品列表 -->
<ItemsControl ItemsSource="{Binding Products}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Border Width="220" Height="372" ...>
                <StackPanel>
                    <!-- 商品主图 -->
                    <Image ... Source="{Binding ImageUri}" />
                    <!-- ★ 内层 ItemsControl:每个商品的多张缩略图 -->
                    <ItemsControl Height="42" ItemsSource="{Binding Thumbnails}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel HorizontalAlignment="Center"
                                            Orientation="Horizontal" />
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <Border Width="34" Height="34"
                                        BorderBrush="#CCCCCC" BorderThickness="1">
                                    <Image Width="30" Height="30"
                                           Source="{Binding ImageUri}" />
                                </Border>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                    <!-- 价格、名称、成交数、评价数... -->
                </StackPanel>
            </Border>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

关键点:ItemsControl 可以任意嵌套——外层遍历商品、内层遍历缩略图,数据到哪一层就渲染到哪一层。


2.5 购物车——每个 Item 有 CheckBox 双向绑定

源码位置:Views/Fore/ForeCartView.xaml:63-118

<ItemsControl ItemsSource="{Binding Items}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Border MinHeight="112" ...>
                <Grid>
                    <CheckBox VerticalAlignment="Center"
                              IsChecked="{Binding IsSelected, Mode=TwoWay}" />
                    <Image ... Source="{Binding Product.ImageUri}" />
                    <TextBlock ... Text="{Binding Product.ProductName}" />
                    <TextBox ... Text="{Binding Quantity,
                                      UpdateSourceTrigger=PropertyChanged}" />
                    <TextBlock ... Text="{Binding Price, StringFormat=¥{0:F2}}" />
                    <Button Content="删除"
                            Command="{Binding DataContext.DeleteItemCommand,
                                      RelativeSource={RelativeSource AncestorType=UserControl}}"
                            CommandParameter="{Binding}" />
                </Grid>
            </Border>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

关键点

  • IsChecked="{Binding IsSelected, Mode=TwoWay}" —— 勾选状态实时回写 Model

  • UpdateSourceTrigger=PropertyChanged —— 输入数量即时更新

  • CommandParameter="{Binding}" —— 把当前 Item 对象传给删除命令


三、核心要点

|
要点
|
说明
|
| — | — |
| 数据源 |
用 ObservableCollection<T>,不要用 List<T>。Observable 才能在增删时自动刷新 UI
|
| 布局三件套 | ItemsPanel
 管排列、ItemTemplate 管样式、ItemContainerStyle 管容器样式
|
| Command 穿透 |
模板内的按钮用 RelativeSource AncestorType=UserControl 找到页面级 ViewModel
|
| State 可视 |
空数据/加载中/错误态用 DataTrigger 切换 Visibility,不要留白屏
|
| 先面板后模板 |
开发顺序:先把 ItemsPanel 布局调好,再填 ItemTemplate 内容
|


四、练习任务

  • [ ] 入门:建一个 List<string> 用 ItemsControl 展示,尝试把默认的垂直排列改成水平排列

  • [ ] 进阶:仿照 ForeHomeView 商品楼层,做一个 3 列的 UniformGrid 商品卡列表

  • [ ] 挑战:实现一个嵌套 ItemsControl——外层是分类、内层是商品缩略图(参考商品列表页)


📖 下一篇:02 · DataTemplate 数据模板

内容概要:本文围绕可变桨叶四旋翼无人机的规范控制与点对点运动模拟展开,重点研究优化推力分配策略在翻转动作中的应用与性能比较。通过Matlab代码实现,构建了四旋翼动力学模型,并设计了多种控制算法以实现精确的姿态调整与轨迹跟踪。研究对比了不同推力分配方案在执行高机动性翻转动作时的稳定性、能耗效率与响应速度,旨在提升无人机在复杂飞行任务中的动态性能与控制精度。该仿真研究为无人机飞控系统的设计与优化提供了理论依据和技术支持。; 适合人群:具备一定自动控制理论基础和Matlab编程能力,从事无人机控制、飞行器动力学或机器人系统研究的科研人员及研究生。; 使用场景及目标:① 实现四旋翼无人机在三维空间中的精确点对点运动控制;② 对比分析不同推力分配策略在执行翻转等高难度动作时的控制效果与能耗表现,优化飞行性能;③ 为无人机自主飞行、特技飞行及复杂环境下的机动控制提供算法验证平台。; 阅读建议:此资源以Matlab仿真为核心,建议读者结合相关控制理论知识,深入理解代码实现细节,重点关注动力学建模、控制律设计与推力分配模块。在学习过程中,应动手调试参数,复现文中翻转动作的仿真结果,并尝试拓展至其他复杂飞行任务,以加深对无人机控制机理的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WPF工业上位机

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值