一、下载
1、 下载NuGet包:LiveChartsCore.SkiaSharpView.WPF
2、全局中文设置:在App.xaml.cs文件添加代码,防止图表中文变“口口”
public partial class App : Application
{
// 设置全局字体-中文
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
LiveCharts.Configure(config => config.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('汉')));
}
}
或者在使用Livecharts的窗口的构造函数中添加中文设置,防止此设置干扰其他窗口控件
3、添加命名空间声明
xmlns:lvc="clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF"
官方文档链接:Overview.Installation - LiveCharts2https://livecharts.dev/docs/WPF/2.0.0-rc4/Overview.Installation
注意下载的NuGet包版本和官方文档版本一致
二、图表
1、饼图
1. MainWindow.xaml代码
添加饼图控件PieChart
<lvc:PieChart Series="{Binding PieSeries}">
</lvc:PieChart>
2. MainWindow.xaml.cs代码
DataContext作为一个容器,提供了UI层和数据层之间的连接点。在MVVM中,DataContext主要用于在View和ViewModel之间建立数据绑定关系,这样View可以通过绑定访问ViewModel中的数据和命令。
public partial class MainWindow : Window
{
private ViewModel _viewModel { get; set; }
public MainWindow()
{
// 设置字体-中文
LiveCharts.Configure(config => config.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('汉')));
_viewModel = new ViewModel();
// 将 ViewModel 设置为主窗口的 DataContext
DataContext = _viewModel;
InitializeComponent();
}
}
3. ViewModel.cs代码
创建ViewModel.cs用来绑定数据、创建图表
ViewModel处理Model提供的数据,将其转换为适合View展示的形式。所以ViewModel需要实现INotifyPropertyChanged接口用来通知UI界面修改数据。
3.1 数据绑定
public class ViewModel : INotifyPropertyChanged
{
// 存储饼图数据
private ISeries[] _PieSeries;
public ISeries[] PieSeries
{
get { return _PieSeries; }
set
{
if (_PieSeries != value)
{
_PieSeries = value;
OnPropertyChanged();
}
}
}
//数据绑定
public event PropertyChangedEventHandler? PropertyChanged;
// [CallerMemberName]用于自动传递调用者的名称。这样在调用 OnPropertyChanged 时,可以省略属性名参数。
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
3.2 创建饼图和饼图数据设置
在ViewModel.cs添加如下代码
public ViewModel()
{
InitPieChart();
}
private void InitPieChart()
{
var titles = new string[] { "A", "B", "C" };
var data = new double[] { 1, 0, 3 };
PieSeries = CreatePieChart(titles, data);
}
private bool _isAllZero; // 判断饼图中是否所有数据都是0
/// <summary>
/// 创建饼图
/// </summary>
/// <param name="titles">饼图标签</param>
/// <param name="data">饼图数据</param>
/// <returns></returns>
private ISeries[] CreatePieChart(string[] titles, double[] data)
{
ISeries[] seriesCollection;
_isAllZero = data.All(x => x == 0);
// 如果所有数据不都为0
if (!_isAllZero)
{
// 创建饼图数据
List<PieSeries<double>> seriesList = new List<PieSeries<double>>();
// 定义一个颜色数组
var colors = new SKColor[] { SKColors.DodgerBlue, SKColors.OrangeRed, SKColors.YellowGreen };
for (int i = 0; i < titles.Length; i++)
{
if (data[i] != 0)
{
var series = new PieSeries<double>
{
// 设置扇形名称
Name = titles[i],
// 设置饼图扇形数据
Values = new double[] { data[i] },
// 设置饼图扇形填充颜色
Fill = new SolidColorPaint(colors[i]),
// 设置数据标签字体大小
DataLabelsSize = 15,
// 设置数据标签颜色
DataLabelsPaint = new SolidColorPaint(SKColors.White),
// 设置数据标签位置
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.Middle,
// 设置数据标签格式化器
DataLabelsFormatter = point => point.Context.Series.Name + ":" + point.Coordinate.PrimaryValue.ToString(),
// DataLabelsFormatter = _ => "", // 隐藏数据标签
};
seriesList.Add(series);
}
}
seriesCollection = seriesList.ToArray();
}
// 如果所有数据都为0,则添加一个虚拟的系列
else
{
seriesCollection = new ISeries[1];
// 添加一个虚拟的系列,确保总有一部分被显示
var virtualSeries = new PieSeries<double>
{
Name = "无",
Values = new double[] { 1 },
Fill = new SolidColorPaint(SKColor.Parse("#55B155")),
// 设置数据标签字体大小
DataLabelsSize = 15,
// 设置数据标签颜色
DataLabelsPaint = new SolidColorPaint(SKColors.White)
{
SKFontStyle = SKFontStyle.Italic,
},
// 设置数据标签位置
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.Middle,
DataLabelsFormatter = point => point.Context.Series.Name ?? "无",
// 提示框文字格式
ToolTipLabelFormatter = _ => "",
};
seriesCollection[0] = virtualSeries;
}
return seriesCollection;
}
左侧为数据包含零的饼图,中间为数据不为零,右侧为数据全为零
2、折线图
与饼图不同的是,折线图属性lineChart是CartesianChart类型,通常用于存储和显示折线图、柱状图等二维坐标系图表。而ISeries[] PieSeries是饼图的数据,每个元素代表饼图中的一个扇区。所以前端绑定也不同。
1. MainWindow.xaml代码
<lvc:CartesianChart Grid.Column="1" Margin="10,10"
Series="{Binding LineChart.Series}"
XAxes="{Binding LineChart.XAxes}"
YAxes="{Binding LineChart.YAxes}"
LegendPosition="Top"
LegendTextPaint="{Binding LegendTextPaint}">
</lvc:CartesianChart>
绑定的属性依次是
- 绑定 Series 属性,显示图表的系列数据
- 绑定 YAxes 属性,配置 Y 轴
- 绑定 YAxes 属性,配置 Y 轴
- 设置图例位置为顶部
- 绑定图例文本的颜色
2. ViewModel.cs代码
2.1 数据绑定
// 折线图
private CartesianChart _LineChart;
public CartesianChart LineChart
{
get { return _LineChart; }
set
{
if (_LineChart != value)
{
_LineChart = value;
OnPropertyChanged();
}
}
}
// 柱状图和折线图图例文字颜色
public SolidColorPaint LegendTextPaint { get; set; } = new SolidColorPaint { Color = SKColors.Black};
2.2 创建折线图
/// <summary>
/// 创建折线图
/// </summary>
/// <param name="titles">图例</param>
/// <param name="data">数据</param>
/// <param name="lables">X轴标签</param>
/// <returns></returns>
private CartesianChart CreateLineChart(string[] titles, double[][] data, string[] lables)
{
ISeries[] seriesCollection = new ISeries[titles.Length];
// 定义一个颜色数组,用于设置折现和图例的颜色
var colors = new SKColor[] { SKColors.Red, SKColors.YellowGreen, SKColors.MediumTurquoise, SKColors.RoyalBlue };
for (int i = 0; i < titles.Length; i++)
{
var series = new LineSeries<double>
{
// 设置折线名称
Name = titles[i],
Values = new List<double>(data[i]), // 使用整个数组作为数据点
Fill = new SolidColorPaint(SKColors.Transparent), // 移除填充颜色
LineSmoothness = 0.2, // 设置线条平滑度
Stroke = new SolidColorPaint(colors[i], 3),// 设置线条颜色和宽度
GeometryStroke = new SolidColorPaint(colors[i], 3), // 设置图例及数据点颜色和宽度
GeometrySize = 8, // 设置数据点大小
// GeometryFill = new SolidColorPaint(SKColors.Transparent), // 设置数据点的填充颜色
};
seriesCollection[i] = series;
}
var XAxes = new Axis[] // 配置 X 轴
{
new Axis
{
IsVisible = true,// 轴是否可见
Name = "日期", // 轴名称
LabelsRotation = 0, // 标签不旋转
TextSize = 15, // 标签文字大小设置为15
ShowSeparatorLines = false, // 不显示X轴坐标线
NamePaint = new SolidColorPaint(SKColors.YellowGreen), // 轴名称Name的颜色
LabelsPaint = new SolidColorPaint(SKColors.Red), // X轴标签的颜色
TicksPaint = new SolidColorPaint(SKColors.Green) { StrokeThickness = 5 } ,// 设置刻度线的颜色和宽度
Position = LiveChartsCore.Measure.AxisPosition.Start, // 设置X轴的位置
Labels = lables, // 设置X轴标签
NameTextSize = 15, // 设置轴名称字体大小
}
};
var YAxes = new Axis[] // 配置 Y 轴
{
new Axis
{
IsVisible = true,// 轴是否可见
Name = "数量", // 轴名称
MinLimit=0, // 设置 Y 轴的最小值(从0开始)
Labeler = value => Math.Floor(value).ToString(), // 设置 Y 轴标签格式,只显示整数
LabelsPaint = new SolidColorPaint(SKColors.Gray), // Y轴标签颜色
SeparatorsPaint = new SolidColorPaint(SKColors.SlateBlue) { StrokeThickness = 1 }, // 设置分隔线的颜色和宽度
}
};
// 创建折线图
var cartesianChart = new CartesianChart()
{
Series = seriesCollection, // 配置折线图
XAxes = XAxes, // 配置 X 轴
YAxes = YAxes, // 配置 Y 轴
};
return cartesianChart;
}
属性说明:
2.3 数据设置
public ViewModel()
{
InitPieChart();
InitLineChart();
}
private void InitLineChart()
{
var titles = new string[] { "A", "B", "C" };
var data = new double[][] {
new double[] { 1, 2, 3 },
new double[] { 4, 5, 6 },
new double[] { 7, 8, 9 }
};
var lables = new string[] { "昨天", "今天", "明天" };
lineChart = CreateLineChart(titles, data, lables);
}
3、柱状图
1. MainWindow.xaml代码
<lvc:CartesianChart Margin="10,10"
Series="{Binding ColumnChart.Series}"
XAxes="{Binding ColumnChart.XAxes}"
YAxes="{Binding ColumnChart.YAxes}"
LegendPosition="Top"
LegendTextPaint="{Binding LegendTextPaint}">
</lvc:CartesianChart>
2. ViewModel.cs代码
2.1 数据绑定
// 柱状图
private CartesianChart _ColumnChart;
public CartesianChart ColumnChart
{
get { return _ColumnChart; }
set
{
if (_ColumnChart != value)
{
_ColumnChart = value;
OnPropertyChanged();
}
}
}
2.2 创建柱状图
/// <summary>
/// 创建柱状图
/// </summary>
/// <param name="titles">柱状图图例</param>
/// <param name="data">柱状图数据</param>
/// <param name="lables">柱状图X轴标签</param>
/// <returns></returns>
private CartesianChart CreateColumnChart(string[] titles, double[][] data, string[] lables)
{
ISeries[] seriesCollection = new ISeries[titles.Length];
var colors = new SKColor[] { SKColors.RoyalBlue, SKColors.LightGreen, SKColors.Goldenrod };
for (int i = 0; i < titles.Length; i++)
{
var series = new ColumnSeries<double, LiveChartsCore.SkiaSharpView.Drawing.Geometries.RectangleGeometry>
{
Name = titles[i],
Values = new List<double>(data[i]),
Fill = new SolidColorPaint(colors[i]),
};
seriesCollection[i] = series;
}
var XAxes = new Axis[] // 配置 X 轴
{
new ()
{
IsVisible = true,// 轴是否可见
//Name = "X Axis", // 轴名称
LabelsRotation = 0, // 标签不旋转
TextSize = 15, // 标签文字大小设置为10
ShowSeparatorLines = false, // 显示坐标线
NamePaint = new SolidColorPaint(SKColors.Black), // 轴名称颜色
LabelsPaint = new SolidColorPaint(SKColors.Black), // 标签颜色
SeparatorsPaint = new SolidColorPaint(SKColors.Gray) { StrokeThickness = 1 }, // 设置分隔线的颜色和宽度
TicksPaint = new SolidColorPaint(SKColors.Gray) { StrokeThickness = 1 } ,// 设置刻度线的颜色和宽度
Position = LiveChartsCore.Measure.AxisPosition.Start, // 设置轴的位置
Labels = lables,
}
};
var YAxes = new Axis[] // 配置 Y 轴
{
new ()
{
IsVisible = true,// 轴是否可见
//Name = "Y Axis", // 轴名称
MinLimit=0, // 设置 Y 轴的最小值
Labeler = value => Math.Floor(value).ToString(), // 设置 Y 轴标签格式,只显示整数
LabelsPaint = new SolidColorPaint(SKColors.Black), // 标签颜色设置为白色
}
};
var cartesianChart = new CartesianChart()
{
Series = seriesCollection,
XAxes = XAxes,
YAxes = YAxes,
};
return cartesianChart;
}
属性说明:
红框标注部分可以设置图例形状,需要注意柱状图设置图例后,图表中每个柱体形状会根据所选图例形状进行改变。其他属性和折线图类似。
官方文档:samples.lines.custom - LiveCharts2
具体图例形状查看文档链接:LiveChartsCore.SkiaSharpView.Drawing.Geometries.StarGeometry - LiveCharts2
2.3 数据设置
public ViewModel()
{
InitPieChart();
InitLineChart();
InitColumnChart();
}
private void InitColumnChart()
{
var titles = new string[] { "数据一", "数据二", "数据三" };
var data = new double[][] {
new double[] { 1, 2, 3, 2, 1 },
new double[] { 4, 5, 6 ,5, 4 },
new double[] { 7, 8, 9, 8, 7 }
};
var lables = new string[] { "星期一", "星期二", "星期三", "星期四", "星期五" };
ColumnChart = CreateColumnChart(titles, data, lables);
}
三、总结
饼图控件为PieChart,而折线图和柱状图的控件都为CartesianChart。
虽然前端使用相同的 CartesianChart控件来展示折线图和柱状图,但后端通过创建不同的数据系列对象(LineSeries或 ColumnSeries),实现折线图和柱状图,折线图用LineSeries,柱状图用ColumnSeries。
题外话,关于SKColors颜色