VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • 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:存储单条折线的数据点,实现INotifyCollectionChanged,数据变化时图表自动更新;
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),避免覆盖旧文件。
基础知识拓展

  1. LiveCharts核心概念
概念 作用说明
CartesianChart 直角坐标系图表,支持折线图、柱状图、散点图等(最常用);
PieChart 饼图,用于展示占比数据;
SeriesCollection 图表的系列容器,每个系列对应一条折线/柱状图;
ChartValues 单系列的数据点集合,支持自动更新;
Axis 坐标轴,控制X/Y轴的标签、格式化、范围;
Tooltip hover提示框,显示数据点的详细信息;
Legend 图例,显示系列的名称和颜色;
  1. 折线图样式定制技巧
    折线填充:把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


相关教程