关于 syncfusion-wpf-kanban-board
面向 WPF 开发者的 Syncfusion SfKanban 看板控件实现指南,用于将任务按工作流阶段组织成卡片和列。内容涵盖泳道、WIP 限制、状态转换规则及卡片拖放。
主要功能
- 01按工作流阶段排列任务卡片
- 02按团队或项目划分泳道
- 03设置列级 WIP 限制
- 04拖放卡片及批量移动
- 05配置允许的状态转换
- 06卡片排序与列重排
适用场景
- 01跟踪软件开发任务和缺陷
- 02按团队成员组织项目任务
- 03限制各工作阶段的任务数量
- 04执行受规则约束的任务状态流转
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ syncfusion/ wpf-ui-components-skills --skill syncfusion-wpf-kanban-board安装后在 Claude Code 中输入/syncfusion-wpf-kanban-board确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/cards.mdcolumns.mdevents.mdgetting-started.mdsorting.mdswimlanes.mdworkflows.md详细介绍
实现 Syncfusion WPF Kanban(SfKanban)
本技能提供有关实现 Syncfusion® WPF Kanban(SfKanban)控件的全面指南。该控件是一种强大的可视化工作流管理系统,可将任务显示为卡片,并将卡片组织在代表不同工作流阶段的列中。
何时使用此技能
在以下情况中立即使用此技能:
- 用户想要创建用于任务或项目管理的看板
- 构建工作流可视化系统(待办、进行中、已完成)
- 实现敏捷项目跟踪看板
- 需要为每个工作流阶段设置进行中(WIP)限制
- 创建支持拖放功能的任务看板
- 使用泳道按团队、项目或自定义条件组织任务
- 管理软件开发工作流或问题跟踪系统
- 需要可视化多个阶段中的任务状态
组件概述
Syncfusion WPF Kanban(SfKanban)可高效地直观呈现工作流各阶段的完成情况。它提供以下功能:
核心功能:
- 卡片:以可视化方式呈现任务,包含标题、说明、标签、图像和优先级指示器
- 列:将工作组织到各个工作流阶段(例如,待处理、进行中、已完成)
- 泳道:按项目、团队、用户或自定义类别对卡片分组
- 进行中(WIP)限制:为每列设置任务数量的最小值和最大值,避免超负荷
- 拖放:直观地在列和泳道之间移动卡片,并支持多卡片(批量)拖放
- 卡片选择:支持单选和多选,并可自定义选中卡片的外观
- 列重新排序:通过拖放重新排列列
- 工作流:定义卡片在特定状态之间允许的转换
- 排序:按优先级、日期或自定义字段对列中的卡片排序
- 事件:提供丰富的卡片交互事件模型(点击、拖动、放下)
- 自定义:全面支持自定义卡片、标题和泳道模板
- 主题:内置浅色和深色主题,并支持系统集成
- 本地化和 RTL:支持多种语言和从右到左的显示
文档与导航指南
入门
📄 阅读: references/getting-started.md
适用于用户需要:
- 通过 NuGet 进行初始设置和安装
- 创建基本看板
- 了解 ItemsSource 绑定
- 使用默认 KanbanModel 或自定义数据模型
- 设置自动生成或手动定义的列
- 应用主题、本地化和 RTL 支持
卡片配置
📄 阅读: references/cards.md
适用于用户需要:
- 了解卡片结构和属性
- 使用 CardTemplate 自定义卡片外观
- 使用卡片指示器和标签
- 实现条件卡片模板(CardTemplateSelector)
- 启用和自定义卡片工具提示
- 选择单张或多张卡片(CardSelectionType)
- 通过多卡片拖放批量移动任务
- 自定义选中卡片的外观(SelectedBorderBrush)
- 以编程方式获取选中的卡片(GetSelectedCards)
- 排查卡片显示问题
列管理
📄 阅读: references/columns.md
适用于用户需要:
- 配置列宽(最小值、最大值、精确值)
- 在自动生成列与手动定义列之间进行选择
- 将类别映射到列
- 自定义列标题
- 以编程方式展开或折叠列
- 按列启用或禁用拖放
- 启用通过拖放重新排列列(AllowColumnReorder)
- 设置多类别列
- 配置 WIP(进行中)限制及其可视化指示器
- 自定义拖放占位符的外观
泳道组织
📄 阅读: references/swimlanes.md
适用于用户需要:
- 按团队、项目或用户分组卡片
- 启用和配置泳道
- 映射泳道属性(SwimlaneKey)
- 自定义泳道标题的外观
- 创建分层卡片组织结构
- 实现基于团队或项目的视图
工作流和状态转换
📄 阅读: references/workflows.md
适用于用户需要:
- 定义卡片在列之间允许的状态转换
- 限制卡片在特定状态之间移动
- 实现工作流验证规则
- 阻止通过拖放将卡片移动到特定列
- 创建类似状态机的工作流
- 管理复杂的工作流状态转换
卡片排序
📄 阅读: references/sorting.md
适用于用户需要:
- 按优先级、日期或自定义字段对列中的卡片排序
- 实现自定义字段排序(升序/降序)
- 设置基于索引的排序,以精确定位
- 在拖放后动态更新排序顺序
- 排序变更后刷新列显示
- 了解如何对自定义数据模型进行排序
事件和交互
📄 阅读: references/events.md
适用于用户需要:
- 处理卡片点击事件(CardTapped)
- 响应拖动事件(CardDragStarting、CardDragOver)
- 处理卡片放置事件(CardDrop)
- 实现 MVVM 命令(CardTappedCommand)
- 访问事件参数和卡片数据
- 阻止或自定义拖放行为
- 处理卡片选择事件(CardSelected、CardDeselected)
- 处理列重新排序事件(ColumnDragStarting、ColumnDragOver、ColumnDrop)
- 在卡片交互中实现业务逻辑
快速入门示例
基本看板设置
<Window xmlns:kanban="clr-namespace:Syncfusion.UI.Xaml.Kanban;assembly=Syncfusion.SfKanban.WPF">
<kanban:SfKanban x:Name="kanban"
ItemsSource="{Binding TaskDetails}">
<kanban:SfKanban.DataContext>
<local:ViewModel/>
</kanban:SfKanban.DataContext>
</kanban:SfKanban>
</Window>
使用 KanbanModel 的 ViewModel
using Syncfusion.UI.Xaml.Kanban;
public class ViewModel
{
public ObservableCollection<KanbanModel> TaskDetails { get; set; }
public ViewModel()
{
TaskDetails = new ObservableCollection<KanbanModel>
{
new KanbanModel
{
Title = "UWP Issue",
ID = "651",
Description = "Fix crosshair label template issue",
Category = "Open",
ColorKey = "High",
Tags = new string[] { "Bug Fixing" }
},
new KanbanModel
{
Title = "Kanban Feature",
ID = "25678",
Description = "Implement drag and drop support",
Category = "In Progress",
ColorKey = "Normal",
Tags = new string[] { "New Feature" }
}
};
}
}
手动定义列
<kanban:SfKanban AutoGenerateColumns="False"
ItemsSource="{Binding TaskDetails}">
<kanban:KanbanColumn Title="To Do" Categories="Open" />
<kanban:KanbanColumn Title="In Progress" Categories="In Progress" />
<kanban:KanbanColumn Title="Done" Categories="Done" />
</kanban:SfKanban>
常见模式
模式 1:自动生成列
适用场景: 用户希望根据数据快速设置并生成列
// Columns automatically generated from Category property values
kanban.AutoGenerateColumns = true;
kanban.ItemsSource = viewModel.TaskDetails;
结果: 根据数据中唯一的 Category 值自动创建列
模式 2:使用可视化指示器设置 WIP 限制
适用场景: 用户需要限制每个阶段的任务数量并显示可视化反馈
<kanban:KanbanColumn Title="In Progress"
Categories="In Progress"
MinimumLimit="2"
MaximumLimit="5" />
结果:
- 数量超过 MaximumLimit 时,错误栏显示为红色
- 数量低于 MinimumLimit 时,错误栏显示为黄色
- 有助于防止工作流瓶颈
模式 3:自定义卡片模板
适用场景: 用户需要自定义卡片外观,而非使用默认外观
<kanban:SfKanban.CardTemplate>
<DataTemplate>
<Border Background="#F3CFCE"
BorderThickness="1"
CornerRadius="3">
<StackPanel Margin="10">
<TextBlock Text="{Binding Title}"
FontWeight="Bold"
FontSize="14" />
<TextBlock Text="{Binding Description}"
FontSize="12"
TextWrapping="Wrap" />
</StackPanel>
</Border>
</DataTemplate>
</kanban:SfKanban.CardTemplate>
DataContext: KanbanModel 实例
模式 4:按团队划分泳道
适用场景: 用户希望按团队或项目组织卡片
<kanban:SfKanban SwimlaneKey="Assignee"
ItemsSource="{Binding TaskDetails}">
</kanban:SfKanban>
结果: 水平泳道行,每个唯一的 Assignee 值对应一行
模式 5:工作流限制
适用场景: 用户希望强制执行特定的卡片状态转换规则
<kanban:SfKanban.Workflows>
<kanban:KanbanWorkflow Category="Open">
<kanban:KanbanWorkflow.AllowedTransitions>
<x:String>In Progress</x:String>
</kanban:KanbanWorkflow.AllowedTransitions>
</kanban:KanbanWorkflow>
<kanban:KanbanWorkflow Category="In Progress">
<kanban:KanbanWorkflow.AllowedTransitions>
<x:String>Done</x:String>
<x:String>Won't Fix</x:String>
</kanban:KanbanWorkflow.AllowedTransitions>
</kanban:KanbanWorkflow>
</kanban:SfKanban.Workflows>
结果:
- “Open”中的卡片只能移至“In Progress”
- “In Progress”中的卡片只能移至“Done”或“Won't Fix”
- 防止无效的状态转换
模式 6:自定义数据模型
适用场景: 用户已有现成的数据模型,不使用 KanbanModel
// Custom model
public class TaskDetails
{
public string Title { get; set; }
public string Description { get; set; }
public string Status { get; set; }
}
// XAML
<kanban:SfKanban ItemsSource="{Binding Tasks}"
ColumnMappingPath="Status">
<kanban:SfKanban.CardTemplate>
</kanban:SfKanban.CardTemplate>
</kanban:SfKanban>
重要提示: 使用自定义模型时,必须定义 CardTemplate
模式 7:多卡片选择与批量拖放
适用场景: 用户需要选择多张卡片,并将它们一起移至其他阶段
<kanban:SfKanban CardSelectionType="Multiple"
ItemsSource="{Binding TaskDetails}">
<kanban:SfKanban.CardStyle>
<kanban:KanbanCardStyle SelectedBorderBrush="Blue"
HoverBorderBrush="LightGray"/>
</kanban:SfKanban.CardStyle>
</kanban:SfKanban>
结果:
- Ctrl + Click 可将单张卡片添加到选择中或从选择中移除
- Shift + Click 可选择同一列中的一组卡片
- 拖动任意已选卡片,即可将所有已选卡片作为单次操作一起移动
- 放置后,已选卡片的相对顺序保持不变
- 无效的工作流状态转换会取消整个拖动操作
在代码中获取选择内容:
var selectedCards = kanban.GetSelectedCards();
模式 8:列重排
适用场景: 用户需要在运行时重新排列工作流阶段
<kanban:SfKanban AllowColumnReorder="True"
AutoGenerateColumns="False"
ItemsSource="{Binding TaskDetails}">
<kanban:KanbanColumn Title="To Do" Categories="Open" />
<kanban:KanbanColumn Title="In Progress" Categories="In Progress" />
<kanban:KanbanColumn Title="Done" Categories="Done" />
</kanban:SfKanban>
结果:
- 拖动列标题可移动整列(标题和卡片)
- 列会插入到放置位置,并推动其他列
- 不设置
AllowColumnReorder即可禁用(默认值:false)
关键属性
SfKanban 属性
| 属性 | 类型 | 用途 | 使用场景 |
|---|---|---|---|
ItemsSource | object | 卡片的数据源 | 始终使用(必需) |
AutoGenerateColumns | bool | 根据 Category 自动创建列 | 快速设置或自定义控制 |
Columns | Collection | 手动定义列 | 当 AutoGenerateColumns = false 时 |
ColumnMappingPath | string | 用于列分类的属性 | 自定义模型(默认值:"Category") |
SwimlaneKey | string | 用于泳道分组的属性 | 按团队/项目组织 |
CardTemplate | DataTemplate | 自定义卡片外观 | 自定义数据模型或样式 |
ColumnHeaderTemplate | DataTemplate | 自定义列标题 | 品牌展示或补充信息 |
SwimlaneHeaderTemplate | DataTemplate | 自定义泳道标题 | 自定义泳道显示 |
MinColumnWidth | double | 最小列宽 | 响应式布局 |
MaxColumnWidth | double | 最大列宽 | 控制列大小 |
ColumnWidth | double | 固定列宽 | 统一列宽 |
SortingMappingPath | string | 用于卡片排序的属性 | 按优先级/日期排列卡片 |
SortingOrder | enum | 升序或降序 | 排序方向 |
Workflows | Collection | 允许的卡片流转 | 工作流验证 |
IndicatorColorPalette | Collection | 指示器的颜色映射 | 优先级/状态颜色 |
IsToolTipEnabled | bool | 启用卡片工具提示 | 悬停时显示卡片补充信息 |
CardSelectionType | KanbanCardSelectionType | 卡片选择模式(Single、Multiple、None) | 单卡片或多卡片选择 |
AllowColumnReorder | bool | 启用列的拖放重排(默认值:false) | 用户自定义列顺序 |
KanbanColumn 属性
| 属性 | 类型 | 用途 | 使用场景 |
|---|---|---|---|
Title | string | 列的显示名称 | 自定义列标题 |
Categories | string | 以逗号分隔的类别 | 将数据映射到列 |
MinimumLimit | int | WIP 最小限制 | 工作流管理 |
MaximumLimit | int | WIP 最大限制 | 防止超载 |
AllowDrag | bool | 启用从列中拖动 | 控制卡片移动 |
AllowDrop | bool | 启用放置到列中 | 限制放置操作 |
IsExpanded | bool | 列的折叠/展开状态 | 控制 UI 状态 |
KanbanModel 属性
| 属性 | 类型 | 描述 | 显示位置 |
|---|---|---|---|
Title | string | 卡片标题 | 顶部,粗体文本 |
ID | object | 唯一标识符 | 默认 UI 中不显示 |
Description | string | 详细文本 | 标题下方 |
Category | object | 列分配 | 决定列的位置 |
Assignee | string | 指派对象 | 用于泳道分组 |
ColorKey | object | 优先级/状态键 | 卡片上的颜色条 |
Tags | string[] | 标签/类别 | 卡片底部 |
ImageURL | Uri | 头像/图标 | 卡片右侧 |
常见用例
1. 软件开发任务看板
场景: 跟踪 Bug 和功能在各开发阶段中的进展
<kanban:SfKanban ItemsSource="{Binding Issues}">
<kanban:KanbanColumn Title="Backlog" Categories="Open,New" />
<kanban:KanbanColumn Title="In Development"
Categories="In Progress"
MaximumLimit="3" />
<kanban:KanbanColumn Title="Testing"
Categories="Testing"
MaximumLimit="5" />
<kanban:KanbanColumn Title="Done"
Categories="Closed,Resolved" />
</kanban:SfKanban>
2. 基于团队的项目管理
场景: 使用泳道按团队成员组织任务
<kanban:SfKanban SwimlaneKey="Assignee"
ItemsSource="{Binding ProjectTasks}">
<kanban:SfKanban.SwimlaneHeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}" Width="30" Height="30"/>
<TextBlock Text="{Binding Title}" Margin="10,0"/>
</StackPanel>
</DataTemplate>
</kanban:SfKanban.SwimlaneHeaderTemplate>
</kanban:SfKanban>
3. 基于优先级排序
场景: 按优先级对每列中的卡片进行排序
<kanban:SfKanban SortingMappingPath="Priority"
SortingOrder="Descending"
ItemsSource="{Binding Tasks}"
CardDragEnd="OnCardDrop">
</kanban:SfKanban>
private void OnCardDrop(object sender, KanbanDragEndEventArgs e)
{
kanban.RefreshKanbanColumn(e.TargetKey.ToString());
}
4. 交互式卡片操作
场景: 处理卡片点击事件以显示详情对话框
kanban.CardTapped += (s, e) => {
var card = e.SelectedCard.DataContext as KanbanModel;
var dialog = new TaskDetailsDialog(card);
await dialog.ShowAsync();
};
故障排除
问题:列未显示
**症状:**看板为空,没有显示任何列
解决方案:
- 确认 AutoGenerateColumns 为 true,或已手动定义 Columns
- 检查 ItemsSource 是否正确绑定
- 确保数据中的 Category 属性有值
- 如果使用 ColumnMappingPath,请确认模型中存在该属性
问题:卡片未显示
**症状:**列已显示,但没有卡片
解决方案:
- 检查 ItemsSource 是否包含数据
- 确认 Category 值与列的 Categories 匹配
- 如果使用自定义模型,请确保已定义 CardTemplate
- 检查 DataContext 是否设置正确
问题:拖放不起作用
**症状:**无法在列之间移动卡片
解决方案:
- 确认源列的 AllowDrag=true(默认值为 true)
- 确保 Workflows 不会限制该转换
- 检查列是否映射了正确的 Categories
问题:WIP 限制不起作用
**症状:**未显示 WIP 限制的视觉指示器
解决方案:
- 确认已为列设置 MinimumLimit 和/或 MaximumLimit
- 检查卡片数量是否确实超出/低于限制
- 确保主题资源已正确加载
问题:泳道未分组
**症状:**所有卡片都在同一行,没有泳道
解决方案:
- 确认已设置 SwimlaneKey 属性
- 检查数据模型中是否存在映射的属性
- 确保数据中的属性值各不相同
- 如果使用 KanbanModel,默认值为 "Assignee"
问题:排序未生效
**症状:**拖放后卡片未排序
解决方案:
- 在 CardDrop 事件中调用 RefreshKanbanColumn()
- 确认 SortingMappingPath 设置为有效属性
- 检查属性类型是否可排序(string、int、DateTime 等)
- 确保已指定 SortingOrder(Ascending/Descending)
最佳实践
- 快速入门时使用 KanbanModel:内置模型提供默认卡片 UI,可节省开发时间
- 自定义模型需要模板:使用自定义数据模型时,务必定义 CardTemplate
- 设置 WIP 限制:实现 MinimumLimit/MaximumLimit,防止工作流出现瓶颈
- 通过 CardDrop 处理排序:使用排序功能时,在放置后调用 RefreshKanbanColumn()
- 使用 Workflows 进行验证:通过 Workflows 属性阻止无效的状态转换
- 优化列宽:为自适应布局设置 MinColumnWidth/MaxColumnWidth
- 利用泳道:按逻辑类别(团队、项目、优先级)对卡片分组
- 自定义指示器:定义 IndicatorColorPalette,以清晰地显示优先级
- 启用工具提示:设置 IsToolTipEnabled=true,以显示更多卡片信息
- 测试主题:确认浅色和深色模式下的外观
边缘情况和注意事项
每列包含多个类别:
- 使用逗号分隔的值:
Categories="Open,New,Backlog" - 所有匹配的卡片都会显示在同一列中
自定义模型要求:
- 必须定义 CardTemplate(默认模板要求使用 KanbanModel)
- 如果属性名不是 "Category",必须设置 ColumnMappingPath
- 模板的 DataContext 是自定义模型实例
工作流限制:
- AllowedTransitions 为空 = 不允许放置卡片
- 未为某个类别定义工作流 = 允许所有转换
- 工作流中的 Category 必须与数据中的 Category 值完全匹配
拖放排序:
- 放置后不会自动应用排序
- 必须在 CardDrop 事件中手动调用 RefreshKanbanColumn()
- 基于索引的排序需要在事件处理程序中自定义实现
泳道分组:
- KanbanModel 的默认泳道键为 "Assignee"
- 自定义模型必须显式设置 SwimlaneKey
- Null 或空值会创建一个名为 "ungrouped" 的泳道