WPF 大屏数据可视化:用 LiveCharts 快速实现带标签 + 图例的饼图
在 WPF 数据可视化场景中(如大屏看板、统计报表),饼图是展示数据占比的核心组件。本文基于
LiveCharts.Wpf.NetCore3 图表库,通过 纯 Code-Behind 方式 实现一个功能完整的饼图,包含多品类占比展示、标签定制、图例配置、鼠标悬浮交互,同时附带所有核心参数的详细说明,新手也能快速落地。
一、前置准备
1. 环境要求
- .NET Core 3.1 及以上版本(或 .NET 5/6/7/8)
- Visual Studio 2019 及以上
2. 安装图表库
通过 NuGet 安装核心包(与折线图案例共用同一库,无需重复安装):
- 右键项目 →「管理 NuGet 程序包」
- 搜索
LiveCharts.Wpf.NetCore3→ 安装最新稳定版
二、完整实现代码
1. XAML 布局(仅定义饼图控件)
前台仅需创建饼图容器,所有逻辑通过后台代码控制:
xml
<Window x:Class="LiveChartsPieDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
Title="饼图参数详解案例" Height="600" Width="900"
Background="#1E1E1E" Loaded="Window_Loaded">
<Grid Margin="20">
<!-- 饼图容器:深色边框+圆角 -->
<Border Background="#2D2D2D" CornerRadius="8" Padding="20">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="35"/> <!-- 标题行 -->
<RowDefinition Height="*"/> <!-- 饼图行 -->
</Grid.RowDefinitions>
<!-- 图表标题 -->
<TextBlock Text="产品品类销售占比分析"
Foreground="White" FontSize="18"
Margin="10,0,0,0" VerticalAlignment="Center"/>
<!-- 饼图核心控件(命名供后台操作) -->
<lvc:PieChart x:Name="pieChart"
Grid.Row="1"
Background="Transparent"
Hoverable="True"
LegendLocation="Right"> <!-- 图例位置(右侧) -->
</lvc:PieChart>
</Grid>
</Border>
</Grid>
</Window>
2. Code-Behind 后台逻辑(核心参数配置)
所有饼图数据、样式、标签、交互逻辑均在后台实现,无需 MVVM 绑定:
csharp
运行
using LiveCharts;
using LiveCharts.Defaults;
using LiveCharts.Wpf;
using System;
using System.Windows;
using System.Windows.Media;
namespace LiveChartsPieDemo
{
public partial class MainWindow : Window
{
// 定时器:模拟实时数据更新(可选,用于动态调整占比)
private System.Timers.Timer _updateTimer;
public MainWindow()
{
InitializeComponent();
}
// 窗口加载时初始化饼图
private void Window_Loaded(object sender, RoutedEventArgs e)
{
InitPieChart(); // 初始化饼图配置
StartRealTimeUpdate(); // 启动实时数据更新(可选)
}
/// <summary>
/// 初始化饼图:配置数据、样式、标签、图例
/// </summary>
private void InitPieChart()
{
#region 1. 定义饼图系列(核心数据+样式)
var pieSeriesCollection = new SeriesCollection
{
// 品类A:占比35%
new PieSeries
{
// ========== 数据相关 ==========
Title = "品类A", // 品类名称(用于图例+标签)
Values = new ChartValues<ObservableValue> { new ObservableValue(35) }, // 占比数值(支持实时更新)
DataLabels = true, // 是否显示标签(占比信息)
LabelPoint = point => $"{point.Title}\n{point.Y}%", // 标签格式(名称+占比)
// ========== 样式相关 ==========
Fill = new SolidColorBrush(Colors.Orange), // 饼图扇区颜色
Stroke = new SolidColorBrush(Color.FromRgb(30, 30, 30)), // 扇区边框色(区分扇区)
StrokeThickness = 2, // 边框宽度
Opacity = 0.9, // 透明度(0-1)
// ========== 交互相关 ==========
HoverPushOut = 15, // 鼠标悬浮时扇区向外偏移距离(视觉突出)
IsHitTestVisible = true // 是否响应鼠标事件
},
// 品类B:占比25%
new PieSeries
{
Title = "品类B",
Values = new ChartValues<ObservableValue> { new ObservableValue(25) },
DataLabels = true,
LabelPoint = point => $"{point.Title}\n{point.Y}%",
Fill = new SolidColorBrush(Color.FromRgb(144, 238, 144)), // 浅绿
Stroke = new SolidColorBrush(Color.FromRgb(30, 30, 30)),
StrokeThickness = 2,
HoverPushOut = 15
},
// 品类C:占比20%
new PieSeries
{
Title = "品类C",
Values = new ChartValues<ObservableValue> { new ObservableValue(20) },
DataLabels = true,
LabelPoint = point => $"{point.Title}\n{point.Y}%",
Fill = new SolidColorBrush(Colors.Purple),
Stroke = new SolidColorBrush(Color.FromRgb(30, 30, 30)),
StrokeThickness = 2,
HoverPushOut = 15
},
// 品类D:占比20%
new PieSeries
{
Title = "品类D",
Values = new ChartValues<ObservableValue> { new ObservableValue(20) },
DataLabels = true,
LabelPoint = point => $"{point.Title}\n{point.Y}%",
Fill = new SolidColorBrush(Colors.Red),
Stroke = new SolidColorBrush(Color.FromRgb(30, 30, 30)),
StrokeThickness = 2,
HoverPushOut = 15
}
};
#endregion
#region 2. 绑定系列+配置标签样式
// 将饼图系列添加到图表
pieChart.Series = pieSeriesCollection;
// 全局标签样式配置(统一控制所有标签)
foreach (var series in pieChart.Series)
{
var pieSeries = (PieSeries)series;
pieSeries.LabelPosition = PieLabelPosition.Outline; // 标签位置(Outline/Inside/Outside)
pieSeries.LabelForeground = Brushes.White; // 标签文字颜色
pieSeries.LabelFontSize = 12; // 标签字体大小
pieSeries.LabelPadding = 5; // 标签与扇区的间距
}
#endregion
#region 3. 配置图例样式
pieChart.Legend = new DefaultLegend
{
Foreground = Brushes.White, // 图例文字颜色
FontSize = 14, // 图例字体大小
Padding = new Thickness(10), // 图例内边距
Margin = new Thickness(20, 0, 0, 0), // 图例外边距
BulletSize = 12, // 图例前小方块大小
Orientation = System.Windows.Controls.Orientation.Vertical, // 图例排列方向(垂直)
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Center
};
#endregion
#region 4. 饼图全局配置
pieChart.DisableAnimations = false; // 是否禁用动画(大数据量建议开启)
pieChart.AnimationSpeed = TimeSpan.FromMilliseconds(800); // 加载动画时长
pieChart.InnerRadius = 60; // 内环半径(0=普通饼图,>0=环形图)
pieChart.Hoverable = true; // 是否支持鼠标悬浮交互
pieChart.DataTooltip = new DefaultTooltip // 自定义悬浮提示框
{
Background = Brushes.DarkSlateGray,
Foreground = Brushes.White,
FontSize = 13,
Padding = new Thickness(10),
CornerRadius = new CornerRadius(4),
TooltipPosition = TooltipPosition.Top // 提示框位置
};
#endregion
}
/// <summary>
/// 模拟实时数据更新(业务场景可替换为接口拉取/MQ推送)
/// </summary>
private void StartRealTimeUpdate()
{
_updateTimer = new System.Timers.Timer(5000); // 每5秒更新一次
_updateTimer.Elapsed += (s, e) =>
{
Dispatcher.Invoke(() =>
{
// 随机调整某个品类的占比(保持总占比100%,这里简化处理)
var random = new Random();
var targetSeriesIndex = random.Next(0, pieChart.Series.Count);
var targetSeries = (PieSeries)pieChart.Series[targetSeriesIndex];
var currentValue = targetSeries.Values[0].Value;
// 随机增减1-3个百分点(避免占比为负或超过50%)
var change = random.Next(-3, 4);
var newValue = Math.Clamp(currentValue + change, 5, 50);
// 更新数据(ObservableValue 支持实时刷新)
targetSeries.Values[0].Value = newValue;
// 调整其他品类占比(简化逻辑:让最后一个品类承担差值)
var lastSeries = (PieSeries)pieChart.Series[pieChart.Series.Count - 1];
var totalChange = currentValue - newValue;
lastSeries.Values[0].Value = Math.Clamp(lastSeries.Values[0].Value + totalChange, 5, 50);
});
};
_updateTimer.Start();
}
// 窗口关闭时释放定时器(防止内存泄漏)
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
_updateTimer?.Stop();
_updateTimer?.Dispose();
}
}
}
三、核心参数详细说明(新手必看)
1. PieSeries 饼图系列参数(核心)
| 参数 | 类型 | 作用 | 可选值 / 推荐示例 |
|---|---|---|---|
Title |
string |
扇区名称(用于图例 + 标签) | "品类A"/"产品1" |
Values |
ChartValues<ObservableValue> |
占比数据(支持实时更新) | new ChartValues<ObservableValue> { new ObservableValue(35) } |
DataLabels |
bool |
是否显示扇区标签 | true(显示)/false(隐藏) |
LabelPoint |
Func<ChartPoint, string> |
标签格式化逻辑 | point => $"{point.Title}\n{point.Y}%"(名称 + 占比) |
LabelPosition |
PieLabelPosition |
标签位置 | Outline(扇区边缘)/Inside(扇区内)/Outside(扇区外) |
Fill |
Brush |
扇区填充色 | Brushes.Orange/new SolidColorBrush(Colors.LightGreen) |
Stroke |
Brush |
扇区边框色 | new SolidColorBrush(Color.FromRgb(30, 30, 30))(深色边框区分扇区) |
StrokeThickness |
int |
边框宽度 | 2(常规)/3(大屏) |
HoverPushOut |
int |
鼠标悬浮偏移距离 | 10-15(视觉突出,大屏建议 15) |
Opacity |
double |
扇区透明度 | 0.9(常规)/0.7(半透明) |
2. PieChart 全局参数
| 参数 | 类型 | 作用 | 推荐配置 |
|---|---|---|---|
Series |
SeriesCollection |
饼图系列集合(多个扇区) | new SeriesCollection { series1, series2, ... } |
Legend |
DefaultLegend |
图例样式配置 | 白色文字 + 垂直排列 + 右侧位置 |
InnerRadius |
int |
内环半径(环形图关键参数) | 0(普通饼图)/60-100(环形图,大屏建议 100) |
DisableAnimations |
bool |
禁用加载 / 更新动画 | false(常规)/true(大数据量) |
AnimationSpeed |
TimeSpan |
动画时长 | TimeSpan.FromMilliseconds(800)(加载流畅) |
LegendLocation |
LegendLocation |
图例位置 | Right(右侧)/Bottom(底部)/Left(左侧) |
DataTooltip |
DefaultTooltip |
悬浮提示框样式 | 深色背景 + 白色文字 + 圆角 + 内边距 |
Hoverable |
bool |
是否支持鼠标悬浮交互 | true(支持)/false(禁用) |
3. DefaultLegend 图例参数
| 参数 | 类型 | 作用 | 推荐示例 |
|---|---|---|---|
Foreground |
Brush |
图例文字颜色 | Brushes.White(适配深色背景) |
FontSize |
int |
图例字体大小 | 14-16(大屏)/12(常规) |
BulletSize |
int |
图例前小方块大小 | 12-14(与字体大小匹配) |
Orientation |
Orientation |
图例排列方向 | Vertical(垂直,节省空间)/Horizontal(水平) |
Margin/Padding |
Thickness |
外边距 / 内边距 | Margin="20,0,0,0"(与饼图保持间距) |
四、运行效果与优化建议
1. 运行效果
- 深色背景适配大屏场景,4 个扇区展示不同品类占比,环形设计更美观;
- 扇区带边框区分,鼠标悬浮时扇区向外偏移,视觉突出;
- 标签显示品类名称 + 占比,图例在右侧垂直排列,清晰易读;
- 每 5 秒自动更新占比数据,动画过渡流畅,无卡顿。
2. 大屏适配优化(重点)
- 尺寸放大:
StrokeThickness设为 3,LabelFontSize设为 16,Legend.FontSize设为 16,BulletSize设为 14; - 环形图优化:
InnerRadius设为 100-150(增大内环,提升大屏视觉效果); - 交互增强:
HoverPushOut设为 15-20(悬浮偏移更明显,远距离可见); - 全屏显示:设置窗口
WindowStyle="None"+WindowState="Maximized",添加 ESC 退出逻辑(同折线图案例); - 颜色适配:采用高对比度颜色(如橙色、浅绿、紫色、红色),避免与深色背景冲突,同时确保扇区颜色不重复。
五、常见问题解决
-
标签重叠或显示不全?方案 1:调整
LabelPosition为Outline(边缘显示);方案 2:增大LabelPadding(标签间距);方案 3:减少标签文字长度。 -
实时更新数据后饼图不刷新?必须使用
ObservableValue作为数据类型(而非double),该类型自带变更通知,支持实时刷新。 -
图例与饼图重叠?调整
Legend.Margin(如Margin="50,0,0,0"),增加图例与饼图的间距,或修改LegendLocation为Bottom(底部显示)。 -
扇区颜色太暗,大屏看不清?选择高亮度、高对比度颜色(如
Colors.LightSeaGreen、Colors.Gold),或降低Opacity至 0.8-0.9,提升视觉辨识度。
六、扩展场景
- 多环饼图:添加多个
PieChart控件叠加,设置不同InnerRadius,实现嵌套环形图; - 数据筛选:添加下拉框选择时间范围,通过修改
Series.Values实现占比数据筛选; - 点击事件:给
PieSeries添加DataClick事件,点击扇区弹窗显示该品类详细数据:csharp运行pieSeries.DataClick += (s, args) => { MessageBox.Show($"品类:{args.Series.Title}\n占比:{args.ChartPoint.Y}%", "品类详情"); }; - 导出功能:结合
System.Windows.Media.Imaging,将饼图导出为图片(PNG/JPG)。
总结
本文基于
LiveCharts.Wpf.NetCore3 实现了一个功能完整的 WPF 饼图,采用 Code-Behind 方式,无需复杂的 MVVM 绑定,新手可快速上手。核心亮点:- 支持环形图 / 普通饼图切换,标签、图例全定制;
- 支持实时数据更新和鼠标悬浮交互,体验更佳;
- 附带详细参数说明和大屏适配方案,实用性强。

浙公网安备 33010602011771号