WPF 开发之旅:从 UI 基础到高级架构 (二)

mindtian 发布于 2025-07-20 196 次阅读


AI 摘要

当列表框能自动排序,却无法正确显示数据?真相藏在这些属性里。

十三、 列表框控件ListBox与数据模版

1. 数据填充与内容属性

决定了 ListBox 中“装什么”以及“从哪儿装”。

属性名 (Property)描述常用用法 / 示例
ItemsSource[核心] 设置或获取用于生成列表项的数据集合。这是数据绑定的入口。ItemsSource="{Binding StudentList}"
Items获取一个 ItemCollection。当不使用 ItemsSource 时,可手动添加项 (ListBoxItem)。两者互斥。<ListBox><ListBoxItem>A</ListBoxItem></ListBox>
HasItems(只读) 获取一个布尔值,指示 ListBox 是否包含任何项。if (myListBox.HasItems) { ... }

2. 显示与模板属性

决定了列表中的每一项“长什么样”。

属性名 (Property)描述常用用法 / 示例
DisplayMemberPath[快捷方式] 指定 ItemsSource 中对象的某个属性路径,直接用该属性的文本值作为显示内容。DisplayMemberPath="Name"
ItemTemplate[灵活方式] 指定一个 DataTemplate,用于完全自定义每一项的视觉外观。可包含图片、多行文本等复杂布局。<ListBox.ItemTemplate><DataTemplate>...</DataTemplate></ListBox.ItemTemplate>
ItemTemplateSelector指定一个数据模板选择器,用于根据数据项的逻辑动态应用不同的 DataTemplate (例如,及格和不及格的学生用不同模板)。ItemTemplateSelector="{StaticResource StudentTemplateSelector}"
ItemContainerStyle[样式核心] 设置或获取应用到每个项的容器 (即 ListBoxItem) 的 Style。可以控制选中、悬浮、禁用等状态下的外观。用来覆写 ListBoxItem 的默认选中色、边距、触发器等。
ItemContainerStyleSelector动态地为不同的 ListBoxItem 容器应用不同的样式。不如 ItemTemplateSelector 常用,但可用于更深层次的样式区分。
ItemsPanel指定用于布局各项的面板。默认是 VirtualizingStackPanel。可以换成 WrapPanel 实现流式布局。<ListBox.ItemsPanel><ItemsPanelTemplate><WrapPanel/></ItemsPanelTemplate></ListBox.ItemsPanel>

3. 选择相关属性

用于控制和获取用户的选择行为。

属性名 (Property)描述常用用法 / 示例
SelectionMode[模式切换] 设置列表的选择模式。<br>• Single : 只能单选(默认)。<br>• Multiple : 可点击多选。<br>• Extended : 可用 Ctrl/Shift 键进行多选。SelectionMode="Extended"
SelectedItems[多选核心] 获取一个包含所有被选中数据项的只读集合。这是处理多选结果的首选方式。foreach (Student s in myListBox.SelectedItems)
SelectedItem获取或设置被选中的数据对象。在多选模式下,通常返回第一个被选中的项。SelectedItem="{Binding CurrentStudent}"
SelectedIndex获取或设置被选中项的索引 (整数)。在多选模式下,返回有焦点的选中项的索引。SelectedIndex = -1; (清空选择)
SelectedValue获取或设置由 SelectedValuePath 指定的选中项的特定属性值var score = (int)myListBox.SelectedValue;
SelectedValuePath与 SelectedValue 配套使用,指定要从 SelectedItem 中提取哪个属性的值。SelectedValuePath="Score" (获取选中学生的 Score)

4. 行为与外观属性

控制 ListBox 本身的通用行为和视觉表现。

属性名 (Property)描述常用用法 / 示例
ScrollViewer.HorizontalScrollBarVisibility(附加属性) 控制水平滚动条的可见性策略 (AutoVisibleHiddenDisabled)。ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility(附加属性) 控制垂直滚动条的可见性策略。ScrollViewer.VerticalScrollBarVisibility="Auto"
BorderBrushBorderThickness设置 ListBox 控件自身的边框颜色和粗细。BorderBrush="Gray" BorderThickness="1"
HorizontalContentAlignment控制每个 ListBoxItem 内部内容的水平对齐。设为 Stretch 可让内容填满项的宽度。HorizontalContentAlignment="Stretch"
IsEnabledWidthHeightMargin标准的 FrameworkElement 属性,用于控制控件的可用状态、尺寸、位置等。IsEnabled="{Binding IsListEnabled}"

5. 常用事件

事件名 (Event)描述何时使用
SelectionChanged[最重要事件] 当用户选择发生改变时(增、删、换)触发。在 Code-behind 中响应用户选择,执行相应逻辑。
MouseDoubleClick当用户在 ListBox 上双击时触发。常用于实现“双击打开”功能。在 ListBoxItem 上监听此事件,获取双击项并执行操作。
ScrollChanged(来自 ScrollViewer) 当滚动位置发生变化时触发。需要监听用户的滚动行为时使用。

十四、 列表视图控件ListView与数据模板

ListView类可以使用ListBox的所有功能

示例

<ListView ItemsSource="{Binding StudentList}">
    <!-- 核心:指定使用 GridView -->
    <ListView.View>
        <GridView>
            <!-- 定义第一列:姓名 -->
            <GridViewColumn Header="姓名" 
                            Width="120" 
                            DisplayMemberBinding="{Binding Name}" />
            <!-- 定义第二列:分数,并使用模板自定义单元格 -->
            <GridViewColumn Header="分数" Width="80">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Score}" 
                                   Foreground="Red" 
                                   FontWeight="Bold" 
                                   HorizontalAlignment="Center"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>

        </GridView>
    </ListView.View>
</ListView>

1. GridView 本身的属性

这些属性作用于整个表格视图,控制着所有列的宏观行为。

属性名描述常用用法
Columns核心属性。这是一个集合,包含了所有要显示的 GridViewColumn 对象。你大部分工作就是在这个集合里添加和配置列。<GridView><GridView.Columns>...</GridView.Columns></GridView>
AllowsColumnReorder一个布尔值,决定用户是否可以通过拖拽列表头来重新排列列的顺序。默认为 trueAllowsColumnReorder="False" (如果你想锁定列的顺序)
ColumnHeaderContainerStyle设置一个 Style,该样式将应用于所有的列标题 (GridViewColumnHeader)。用于统一修改所有表头的字体、背景、边框等。设置一个带触发器的样式,实现鼠标悬浮时表头变色。
ColumnHeaderTemplate设置一个 DataTemplate,用于自定义所有列标题的内容。比如在所有标题文字前加一个统一的图标。...<DataTemplate><StackPanel>...</StackPanel></DataTemplate>...
ColumnHeaderToolTip为所有的列标题设置一个统一的工具提示。ColumnHeaderToolTip="点击表头可排序"

2. GridViewColumn 的常用属性

分类属性名描述常用用法 / 示例
标题相关Header设置列标题上显示的文本内容。Header="学生姓名"
HeaderTemplate单个列标题指定一个 DataTemplate,用于自定义其复杂内容(如图标+文字)。<GridViewColumn.HeaderTemplate>...
HeaderContainerStyle单个列标题应用一个特定的 Style优先级高于 GridView.ColumnHeaderContainerStyle
内容显示DisplayMemberBinding[快捷方式] 将单元格的内容直接绑定到数据对象的某个属性上。只适用于显示简单的文本。DisplayMemberBinding="{Binding Name}"
(最重要)CellTemplate[灵活方式] 提供一个 DataTemplate 来完全自定义单元格的显示方式。当需要显示颜色、图标、进度条或进行复杂布局时使用。<br>注意:DisplayMemberBinding 和 CellTemplate 通常只用其一。<GridViewColumn.CellTemplate><DataTemplate>...</DataTemplate>
宽度控制Width设置列的宽度。<br>• 固定值Width="120"<br>• 自动Width="Auto" (根据内容自动调整宽度)Width="100"
MinWidth / MaxWidth设置列的最小/最大宽度,限制用户拖拽调整的范围。MinWidth="50"MaxWidth="300"

二十五、 MVVM 框架

WPF学习笔记(25)MVVM框架与项目实例_wpf mvvm-CSDN博客

1. 概述

一种软件架构方式。它是Model-View-ViewModel的简写,分别表示模型、视图和视图模型。有助于将应用程序的界面和业务代码分离。

  • 视图负责定义用户在屏幕上看到的界面外观
  • 模型是封装数据类和业务逻辑
  • 视图模型实现视图可以数据绑定到的属性和命令,并通过更改通知事件通知视图更新

2. ICommand 接口

包含三个成员

  • Execute

void Execute(object parameter)

定义了当命令被触发时要执行的操作

parameter 一个可选的参数,可以从视图传递过来

  • CanExecute

bool CanExecute(object parameter)

定义了命令是否可以被执行

  • CanExecuteChanged

当CanExecute的返回值发生变化时需要触发事件

event EventHandler CanExecuteChanged

二十六、 MVC 模式

1. 概念

  • 模型(Model):负责处理应用程序的业务逻辑和数据访问。
  • 视图(View):负责展示数据给用户。
  • 控制器(Controller):作为模型和视图之间的桥梁,负责处理用户的输入,调用模型的方法来处理业务逻辑,并选择合适的视图来展示结果。

2. 与 MVVM 的区别

  • MVVM 中的 View:主动,通过数据绑定自动更新
  • MVC 中的 View:被动,由 Controller 填充和返回

3. 控制器基础

3.1. 控制器的定义与创建

控制器是处理用户的核心组件,每个控制器类通常对应一个功能模块。

  • 命名规范:控制器应以"Controller"结尾。
  • 继承基类:需要继承Controller积累。
  • 添加方法:控制器类中可以定义多个方法,每个方法对应一个用户请求的处理逻辑。

控制器的发现逻辑

ASP.NET Core MVC 使用约定来发现控制器。默认情况下,框架会查找所有继承自Controller基类的类,并将其视为控制器。

如果需要自定义控制器的发现逻辑,可以通过配置 ControllerOptions 来实现。

3.2. 控制器生命周期

生命周期阶段

  1. 创建:当一个请求到达时,框架会根据路由配置创建一个控制器实例。控制器的构造函数会被调用,依赖注入的服务也会在这个阶段被注入。
  2. 执行操作方法:控制器实例创建完成之后,框架会调用相应的操作方法来处理请求。操作方法的执行结果通常是一个 IActionResult 对象,表示响应的内容。
  3. 销毁:请求处理完成后,控制器实例会被销毁。在销毁之前,可以执行一些清理工作。

操作方法的生命周期

  1. 路由匹配
  2. 控制器实例化
  3. 控制器初始化
  4. 操作方法选择
  5. 模型绑定
  6. 模型验证
  7. 授权检查
  8. Action 过滤器执行
  9. 操作方法执行
  10. 结果过滤器执行
  11. 异常处理
  12. 响应生成和发送

4. 控制器方法类型

4.1. HTTP 方法与控制器方法映射

默认映射

  • GET 方法:默认情况下,控制器会响应 GET 请求。
  • POST 方法:对于需要提交数据的操作,如表单提交,通常使用POST方法。可以通过 [HttpPost] 特性明确指定方法响应 POST 请求。

显示映射

  • 其他 HTTP 方法:处理 GET 和 POST,还可以通过特性显示映射其他 HTTP 方法,如 PUT、DELETE等。

路由与方法映射

  • 路由参数
  • 查询字符串参数

4.2. 动作方法返回类型

视图结果

  • View:返回一个视图页面。

重定向结果

  • RedirectToAction:重定向到另一个控制器方法。
  • RedirectToRoute:根据路由或路由参数进行重定向

JSON 结果

  • JsonResult:返回 JSON 格式的数据。这对于构建 API 或前端框架交互非常有用。

文件结果

  • FileContentResult:返回文件内容。

状态码结果

  • BadRequest:返回 400 状态码,表示请求无效。
  • NotFound:返回 404 状态码,表示资源未找到。

5. 控制器方法参数绑定

5.1. 路由参数绑定

路由参数是通过 URL 传递给控制器方法的参数。通过路由参数,可以获取用户请求中特定的资源标识符。

二七、路由

1. 路由是什么?

路由是一个机制,负责接收所有请求,然后根据请求的 URL 地址,决定应该由控制器的某个具体方法来处理这个请求。

2. 有什么用?

请求分发和创建优雅的 URL。

3. 怎么用?

使用特性来在代码中直接定义路由规则。

4. 用在什么地方?

Web 技术的后端开发中。