-
C#操作图表可视化——销售数据折线图
第二部分:桌面应用开发
9.图表可视化——销售数据折线图
实例介绍
之前做销售管理工具时,每月底整理数据都要把Excel表格翻烂:老板要月度销售趋势,得手动算增长率、插折线图,慢得要死;业务员问自己负责的产品卖得咋样,得筛选半天数据。后来用LiveCharts做了折线图:把月度销售额、不同产品的销售对比直接可视化,hover就能看具体数值,还能缩放看细节。老板说“终于不用瞪着表格找趋势了”,业务员也能快速定位自己的产品表现。这节就带你vb.net教程C#教程python教程SQL教程access 2010教程给销售工具加折线图,彻底解决数据可视化的痛点。
需求分析
折线图要解决“数据趋势不直观”的问题,具体需求如下:
1.核心展示:清晰呈现月度销售额趋势(单系列)、不同产品的销售对比(多系列);
2.交互功能:hover显示数据详情、X轴缩放/平移(查看特定时间段)、图例切换(隐藏/显示某产品数据);
3.样式统一:和全局主题(如PrimaryColor)保持一致,折线粗细、点形状符合品牌风格;
4.数据更新:支持实时刷新(比如每小时更新销售数据)或手动刷新;
5.导出功能:把图表保存为PNG图片(用于汇报);
6.性能优化:数据量大时(比如一年的日度数据)不卡顿,支持抽样显示。
代码实现
前置条件:.NET 6+、WPF;需安装NuGet包 LiveCharts.Wpf(版本2.0+);延续销售管理工具场景,定义SalesData模型和SalesViewModel。
场景1:基础折线图(月度销售额)
用折线图展示2024年1-12月的总销售额,核心是绑定SeriesCollection和坐标轴数据。
步骤1:安装LiveCharts
在NuGet包管理器中搜索并安装 LiveCharts.Wpf。
步骤2:MainWindow.xaml添加折线图
xml
<Window xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
...>
<Grid Margin="10">
<!-- 基础折线图 -->
<lvc:CartesianChart x:Name="SalesChart"
Series="{Binding TotalSalesSeries}"
Margin="10"
FontSize="14">
<!-- X轴:月份 -->
<lvc:CartesianChart.AxisX>
<lvc:Axis Title="月份"
Labels="{Binding Months}"
FontSize="12"
Foreground="{DynamicResource TextColor}"/>
</lvc:CartesianChart.AxisX>
<!-- Y轴:销售额(格式化为货币) -->
<lvc:CartesianChart.AxisY>
<lvc:Axis Title="销售额(元)"
LabelFormatter="{Binding YFormatter}"
FontSize="12"
Foreground="{DynamicResource TextColor}"/>
</lvc:CartesianChart.AxisY>
<!-- Hover提示框 -->
<lvc:CartesianChart.Tooltip>
<lvc:DefaultTooltip Foreground="White"
Background="{DynamicResource PrimaryColor}"
FontSize="12"/>
</lvc:CartesianChart.Tooltip>
</lvc:CartesianChart>
</Grid>
</Window>
步骤3:定义SalesData模型和SalesViewModel
csharp
// SalesData模型:存储单条销售数据
public class SalesData
{
public string Month { get; set; } // 月份(如"1月")
public double TotalAmount { get; set; } // 总销售额
public double ProductA { get; set; } // 产品A销售额
public double ProductB { get; set; } // 产品B销售额
}
// SalesViewModel:处理销售数据逻辑
public partial class SalesViewModel : ObservableObject
{
// 折线图系列集合(核心绑定对象)
[ObservableProperty]
private SeriesCollection _totalSalesSeries = new();
// X轴标签(月份)
[ObservableProperty]
private string[] _months = { "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月" };
// Y轴格式化函数(转为货币格式)
public Func<double, string> YFormatter { get; } = value => $"{value:N0}元";
public SalesViewModel()
{
// 模拟2024年月度销售数据
var monthlySales = new double[] { 12000, 15000, 18000, 16000, 20000, 22000, 25000, 23000, 26000, 28000, 30000, 32000 };
// 添加总销售额折线
TotalSalesSeries.Add(new LineSeries
{
Values = new ChartValues<double>(monthlySales), // 绑定数据点
Title = "总销售额", // 图例名称
StrokeThickness = 2, // 折线粗细
Stroke = new SolidColorBrush((Color)Application.Current.Resources["PrimaryColor"]), // 折线颜色(全局主题)
Fill = Brushes.Transparent, // 折线下方不填充
PointGeometry = DefaultGeometries.Circle, // 数据点形状(圆形)
PointGeometrySize = 8 // 数据点大小
});
}
}
步骤4:MainWindow绑定ViewModel
csharp
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new SalesViewModel();
}
}
场景2:多系列对比(产品A/B销售对比)
在基础折线图上添加产品A、产品B的销售数据,实现多系列对比。
步骤1:ViewModel添加多系列数据
csharp
// SalesViewModel中添加多系列集合
[ObservableProperty]
private SeriesCollection _productSalesSeries = new();
public SalesViewModel()
{
// 模拟产品A/B的月度数据
var productA = new double[] { 5000, 6000, 7000, 6500, 8000, 9000, 10000, 9500, 11000, 12000, 13000, 14000 };
var productB = new double[] { 7000, 9000, 11000, 9500, 12000, 13000, 15000, 13500, 15000, 16000, 17000, 18000 };
// 添加产品A折线
ProductSalesSeries.Add(new LineSeries
{
Values = new ChartValues<double>(productA),
Title = "产品A",
StrokeThickness = 2,
Stroke = Brushes.BlueViolet,
PointGeometry = DefaultGeometries.Triangle,
PointGeometrySize = 8
});
// 添加产品B折线
ProductSalesSeries.Add(new LineSeries
{
Values = new ChartValues<double>(productB),
Title = "产品B",
StrokeThickness = 2,
Stroke = Brushes.ForestGreen,
PointGeometry = DefaultGeometries.Diamond,
PointGeometrySize = 8
});
}
步骤2:XAML切换到多系列图表
xml
<!-- 替换之前的TotalSalesSeries为ProductSalesSeries -->
<lvc:CartesianChart Series="{Binding ProductSalesSeries}"
LegendLocation="Top" <!-- 图例位置(顶部) -->
...>
场景3:交互功能(缩放/平移/图例切换)
添加X轴缩放、平移,以及图例点击隐藏/显示系列的功能。
步骤1:XAML开启交互
xml
<lvc:CartesianChart Series="{Binding ProductSalesSeries}"
LegendLocation="Top"
ZoomingMode="X" <!-- X轴允许缩放 -->
PanningMode="X" <!-- X轴允许平移 -->
Hoverable="True" <!-- 允许hover显示详情 -->
...>
步骤2:图例切换功能(LiveCharts自带)
LiveCharts的图例默认支持点击切换系列显示/隐藏,无需额外代码:点击“产品A”图例,产品A的折线会隐藏;再点击则显示。
场景4:数据更新(实时刷新)
模拟每小时更新一次销售数据,实现图表实时刷新。
步骤1:ViewModel添加定时刷新逻辑
csharp
public SalesViewModel()
{
// 初始化数据...
// 定时刷新(每小时更新一次,这里简化为10秒)
var timer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(10)
};
timer.Tick += (s, e) => UpdateSalesData();
timer.Start();
}
// 模拟更新销售数据
private void UpdateSalesData()
{
// 获取最后一个月的数据,增加随机值(模拟新销售)
var lastMonthTotal = (double)TotalSalesSeries[0].Values.Last();
TotalSalesSeries[0].Values.Add(lastMonthTotal + new Random().Next(1000, 3000));
// 移除第一个月的数据(保持12个月的窗口)
TotalSalesSeries[0].Values.RemoveAt(0);
// 更新月份标签(模拟下一个月)
Months = Months.Skip(1).Concat(new[] { $"{Months.Length+1}月" }).ToArray();
}
场景5:导出图表(保存为PNG)
添加“导出图表”按钮,把折线图保存为图片用于汇报。
步骤1:XAML添加导出按钮
xml
<Button Content="导出图表"
Click="ExportChart_Click"
Margin="10"
Style="{StaticResource PrimaryButtonStyle}"/>
步骤2:MainWindow添加导出逻辑
csharp
private void ExportChart_Click(object sender, RoutedEventArgs e)
{
// 获取图表控件
var chart = SalesChart as CartesianChart;
if (chart == null) return;
// 创建位图渲染器(大小和图表实际大小一致)
var bitmap = new RenderTargetBitmap(
(int)chart.ActualWidth,
(int)chart.ActualHeight,
96, 96,
PixelFormats.Pbgra32);
// 渲染图表到位图
bitmap.Render(chart);
// 编码为PNG
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
// 保存到桌面
var savePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), $"销售图表_{DateTime.Now:yyyyMMddHHmmss}.png");
using (var stream = new FileStream(savePath, FileMode.Create))
{
encoder.Save(stream);
}
MessageBox.Show($"图表已导出到:
{savePath}", "导出成功", MessageBoxButton.OK, MessageBoxImage.Information);
}
逐行讲解
场景1:基础折线图核心代码
1.LiveCharts控件引用:xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf" → 导入LiveCharts的WPF控件;
2.CartesianChart:LiveCharts的直角坐标系图表控件,支持折线图、柱状图等;
3.SeriesCollection:图表的核心数据容器,每个LineSeries对应一条折线;
4.ChartValues
5.YFormatter:Y轴数据格式化函数,把数值转为“12,000元”这样的货币格式;
6.LineSeries属性:
1.StrokeThickness:折线粗细,2px比较合适;
2.Stroke:折线颜色,绑定全局主题的PrimaryColor;
3.PointGeometry:数据点形状,DefaultGeometries.Circle是圆形;
4.Fill:折线下方填充色,设为透明避免遮挡其他系列。
场景2:多系列对比
1.多Series添加:在SeriesCollection中添加多个LineSeries,每个对应一个产品的数据;
2.图例位置:LegendLocation="Top"把图例放在顶部,方便用户切换系列;
3.不同形状区分:产品A用三角形(Triangle)、产品B用菱形(Diamond),避免颜色相近时混淆。
场景3:交互功能
1.ZoomingMode="X":仅允许X轴缩放(拖动鼠标左键框选区域放大);
2.PanningMode="X":允许X轴平移(按住鼠标右键拖动);
3.图例切换:LiveCharts自带的功能,点击图例项即可隐藏/显示对应系列,无需额外代码。
场景4:实时刷新
1.DispatcherTimer:WPF中用于UI线程定时任务的计时器(避免跨线程问题);
2.数据更新逻辑:添加新数据点到ChartValues末尾,移除开头的旧数据,保持窗口大小不变;
3.自动更新:ChartValues实现了INotifyCollectionChanged,所以数据变化时图表会自动刷新。
场景5:导出图表
1.RenderTargetBitmap:WPF中用于渲染UI元素到位图的类;
2.PngBitmapEncoder:把位图编码为PNG格式;
3.保存路径:用Environment.SpecialFolder.Desktop获取桌面路径,避免硬编码;
4.文件名:添加时间戳(yyyyMMddHHmmss),避免覆盖旧文件。
基础知识拓展
- LiveCharts核心概念
| 概念 | 作用说明 |
|---|---|
| CartesianChart | 直角坐标系图表,支持折线图、柱状图、散点图等(最常用); |
| PieChart | 饼图,用于展示占比数据; |
| SeriesCollection | 图表的系列容器,每个系列对应一条折线/柱状图; |
|
ChartValues |
单系列的数据点集合,支持自动更新; |
| Axis | 坐标轴,控制X/Y轴的标签、格式化、范围; |
| Tooltip | hover提示框,显示数据点的详细信息; |
| Legend | 图例,显示系列的名称和颜色; |
-
折线图样式定制技巧
折线填充:把LineSeries.Fill设为半透明颜色(如new SolidColorBrush(Color.FromArgb(50, 33, 150, 243))),增强视觉效果;
网格线:通过Axis.MajorGrid设置网格线样式,比如隐藏X轴网格线:
xml
<lvc:Axis.MajorGrid>
<lvc:Grid Stroke="Transparent"/>
</lvc:Axis.MajorGrid>
坐标轴范围:通过Axis.MinValue/MaxValue固定坐标轴范围,避免数据波动时图表“跳来跳去”;
动画效果:添加Series.AnimationDuration(如TimeSpan.FromSeconds(0.5)),让数据更新时有平滑动画。
3. 性能优化(大数据量场景)
抽样显示:当数据点超过1000时,用LineSeries.SamplingFunction抽样数据,减少渲染压力:
csharp
LineSeries.SamplingFunction = SamplingFunctions.MinMax; // 保留每个区间的最大/最小值
隐藏数据点:把PointGeometrySize设为0,隐藏数据点(仅显示折线);
虚拟滚动:用LiveCharts.Wpf.Virtualization插件实现虚拟滚动(适合超大数据量)。
4. 其他图表类型快速切换
柱状图:把LineSeries换成ColumnSeries;
散点图:把LineSeries换成ScatterSeries;
饼图:用PieChart控件,SeriesCollection中添加PieSeries:
csharp
PieSeries.Add(new PieSeries
{
Values = new ChartValues<double> { 15, 25, 60 },
Labels = new[] { "产品A", "产品B", "其他" },
Title = "产品占比"
});
总结
折线图是趋势可视化的核心工具,LiveCharts在WPF中实现起来简单高效。关键要点:
1.核心绑定:用SeriesCollection和ChartValues绑定数据,实现自动更新;
2.交互优化:开启缩放/平移、图例切换,提升用户体验;
3.样式统一:绑定全局主题颜色,保持产品风格一致;
4.性能注意:大数据量时用抽样、隐藏数据点等技巧;
5.拓展性:快速切换到柱状图、饼图等其他类型,满足不同场景需求。
比如销售工具中,折线图让老板一眼看到趋势,业务员快速定位产品问题,导出功能方便汇报——这就是可视化的价值:让数据说话,而不是让用户猜。掌握这些技巧,你可以轻松实现专业级的图表可视化功能!
本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49468.html










