WPF 绘制图表 - LiveCharts 使用指南
LiveCharts 是一款功能强大且界面美观的 WPF 图表绘制类库,相比其他同类库,其 UI 风格更加多样、现代化,支持丰富的动画效果和交互功能。
以下是基于 LiveCharts 实现多种常用图表的详细示例。
准备工作
在使用 LiveCharts 前,需通过 NuGet 安装以下两个核心包:
bash
Install-Package LiveCharts.Wpf
Install-Package LiveCharts
确保在 XAML 文件中添加命名空间引用:
xml
xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
1、甘特图(Gantt Chart)
前台 View 代码
xml
<lvc:CartesianChart Grid.Row="2" Zoom="None" Margin="0,40">
<lvc:CartesianChart.AxisX>
<lvc:Axis Style="{StaticResource FontChartAxis}"
LabelFormatter="{Binding Path=Formatter}"
MinValue="{Binding Path=From, Mode=TwoWay}"
MaxValue="{Binding Path=To, Mode=TwoWay}">
<lvc:Axis.Separator>
<lvc:Separator Stroke="#33ffffff" StrokeDashArray="10"/>
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisX>
<lvc:CartesianChart.AxisY>
<lvc:Axis Style="{StaticResource FontChartAxis}"
Labels="{Binding Path=Labels}">
<lvc:Axis.Separator>
<lvc:Separator Stroke="#33ffffff" StrokeDashArray="10"/>
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisY>
<lvc:CartesianChart.Series>
<lvc:RowSeries Style="{StaticResource FontRowSeries}"
Fill="#008bd3"
LabelsPosition="Parallel"
DataLabels="True"
Values="{Binding Path=Values}"/>
</lvc:CartesianChart.Series>
</lvc:CartesianChart>
后台 ViewModel 代码
csharp
private double _from;
private double _to;
private Func<double, string> _formatter;
private string[] _labels;
private ChartValues<GanttPoint> _values;
public double From { get => _from; set { _from = value; NotifyOfPropertyChange(() => From); } }
public double To { get => _to; set { _to = value; NotifyOfPropertyChange(() => To); } }
public Func<double, string> Formatter { get => _formatter; set { _formatter = value; NotifyOfPropertyChange(() => Formatter); } }
public string[] Labels { get => _labels; set { _labels = value; NotifyOfPropertyChange(() => Labels); } }
public ChartValues<GanttPoint> Values { get => _values; set { _values = value; NotifyOfPropertyChange(() => Values); } }
public void ShowGanttChart()
{
var now = DateTime.Now;
Values = new ChartValues<GanttPoint>
{
new GanttPoint(now.Ticks, now.AddSeconds(2).Ticks),
new GanttPoint(now.AddSeconds(1).Ticks, now.AddSeconds(3).Ticks),
new GanttPoint(now.AddSeconds(3).Ticks, now.AddSeconds(5).Ticks),
new GanttPoint(now.AddSeconds(5).Ticks, now.AddSeconds(8).Ticks),
new GanttPoint(now.AddSeconds(6).Ticks, now.AddSeconds(10).Ticks)
};
Formatter = value => new DateTime((long)value).ToString("MM-dd HH:mm:ss");
Labels = new[]
{
"原材料出库", "智能装配", "个性化定制", "智能包装", "智能仓储"
};
From = Values.First().StartPoint;
To = Values.Last().EndPoint;
}
说明 :
GanttPoint用于表示时间区间,X 轴为时间(以Ticks表示),Y 轴为任务名称。
2、进度环(Gauge Chart)
前台 View 代码
xml
<lvc:Gauge Grid.Row="0"
GaugeBackground="#11ffffff"
HighFontSize="24"
Uses360Mode="False"
From="0" To="100"
InnerRadius="35"
Value="{Binding OrderProgress}">
<!-- 调整起始角度为顶部(0°),方向为逆时针 -->
<lvc:Gauge.GaugeRenderTransform>
<TransformGroup>
<RotateTransform Angle="90"/>
<ScaleTransform ScaleX="-1"/>
</TransformGroup>
</lvc:Gauge.GaugeRenderTransform>
<!-- 设置渐变色填充 -->
<lvc:Gauge.GaugeActiveFill>
<LinearGradientBrush>
<GradientStop Color="#539fff" Offset="0.0" />
<GradientStop Color="#00eaff" Offset="0.5" />
<GradientStop Color="#6af0ff" Offset="1.0" />
</LinearGradientBrush>
</lvc:Gauge.GaugeActiveFill>
</lvc:Gauge>
后台 ViewModel 代码
csharp
private double _orderProgress;
public double OrderProgress
{
get => _orderProgress;
set { _orderProgress = value; NotifyOfPropertyChange(() => OrderProgress); }
}
private void ShowGauge()
{
OrderProgress = 90; // 设置进度为 90%
}
用途:常用于展示完成率、健康度、设备状态等指标。
3、柱状堆积图(Stacked Column Chart)
前台 View 代码
xml
<lvc:CartesianChart Grid.Column="1" LegendLocation="Right" Margin="20,0">
<lvc:CartesianChart.AxisX>
<lvc:Axis Style="{StaticResource FontChartAxis}"
Labels="{Binding Labels}"
Title="时间">
<lvc:Axis.Separator>
<lvc:Separator Step="5" Stroke="#33ffffff" StrokeDashArray="10"/>
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisX>
<lvc:CartesianChart.AxisY>
<lvc:Axis Style="{StaticResource FontChartAxis}" Title="数量">
<lvc:Axis.Separator>
<lvc:Separator Stroke="#33ffffff" StrokeDashArray="10"/>
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisY>
<lvc:CartesianChart.Series>
<lvc:StackedColumnSeries Style="{StaticResource FontStackedColumnSeries}"
Fill="#222222"
LabelsPosition="Merged"
MaxColumnWidth="20"
DataLabels="True"
Values="{Binding V1}"
Title="黑色U盘"/>
<lvc:StackedColumnSeries Style="{StaticResource FontStackedColumnSeries}"
Fill="#26def2"
LabelsPosition="Merged"
MaxColumnWidth="20"
DataLabels="True"
Values="{Binding V2}"
Title="蓝色U盘"/>
<lvc:StackedColumnSeries Style="{StaticResource FontStackedColumnSeries}"
Fill="#ee6363"
LabelsPosition="Merged"
MaxColumnWidth="20"
DataLabels="True"
Values="{Binding V3}"
Title="红色U盘"/>
</lvc:CartesianChart.Series>
<lvc:CartesianChart.ChartLegend>
<lvc:DefaultLegend BulletSize="12" Style="{StaticResource FontChartLegend}"/>
</lvc:CartesianChart.ChartLegend>
</lvc:CartesianChart>
后台 ViewModel 代码
csharp
private string[] _labels;
private IChartValues _v1, _v2, _v3;
public string[] Labels { get => _labels; set { _labels = value; NotifyOfPropertyChange(() => Labels); } }
public IChartValues V1 { get => _v1; set { _v1 = value; NotifyOfPropertyChange(() => V1); } }
public IChartValues V2 { get => _v2; set { _v2 = value; NotifyOfPropertyChange(() => V2); } }
public IChartValues V3 { get => _v3; set { _v3 = value; NotifyOfPropertyChange(() => V3); } }
private void ShowStackedColumn()
{
V1 = new ChartValues<ObservableValue> { 5, 8, 2, 4, 6, 2, 9, 4, 6, 2, 9, 3 };
V2 = new ChartValues<ObservableValue> { 5, 8, 2, 4, 6, 2, 9, 4, 6, 2, 9, 3 };
V3 = new ChartValues<ObservableValue> { 5, 8, 2, 4, 6, 2, 9, 4, 6, 2, 9, 3 };
Labels = new[] { "1月", "2月", "3月", "4月", "5月", "6月",
"7月", "8月", "9月", "10月", "11月", "12月" };
}
特点:适用于展示多类别在不同时间段的总量构成。
4、饼状图(Pie Chart)
方式一:静态定义 Series
xml
<lvc:PieChart Grid.Column="0" Margin="80,25" LegendLocation="Right" InnerRadius="35">
<lvc:PieChart.Series>
<lvc:PieSeries Style="{StaticResource FontPieSeries}" Fill="#222222" DataLabels="True" Values="4" Title="黑色U盘"/>
<lvc:PieSeries Style="{StaticResource FontPieSeries}" Fill="#26def2" DataLabels="True" Values="5" Title="蓝色U盘"/>
<lvc:PieSeries Style="{StaticResource FontPieSeries}" Fill="#ee6363" DataLabels="True" Values="6" Title="红色U盘"/>
</lvc:PieChart.Series>
<lvc:PieChart.ChartLegend>
<lvc:DefaultLegend BulletSize="12" Style="{StaticResource FontChartLegend}"/>
</lvc:PieChart.ChartLegend>
</lvc:PieChart>
方式二:动态绑定 Series(推荐)
前台代码
xml
<lvc:PieChart Name="Chart"
Grid.Row="1"
Grid.Column="3"
Grid.ColumnSpan="4"
Series="{Binding OrderCountSeries}"
Margin="0,0,35,0"
LegendLocation="Right"
InnerRadius="25">
<lvc:PieChart.ChartLegend>
<lvc:DefaultLegend BulletSize="18" Style="{StaticResource FontDefaultStyle}"/>
</lvc:PieChart.ChartLegend>
</lvc:PieChart>
后台代码
csharp
private SeriesCollection _orderCountSeries;
public SeriesCollection OrderCountSeries
{
get => _orderCountSeries;
set { _orderCountSeries = value; NotifyOfPropertyChange(() => OrderCountSeries); }
}
public ObservableValue OrangeOrderCount { get; set; } = new ObservableValue();
public ObservableValue AppleOrderCount { get; set; } = new ObservableValue();
public ObservableValue PearOrderCount { get; set; } = new ObservableValue();
private void InitializeChartSeries()
{
OrderCountSeries = new SeriesCollection
{
new PieSeries
{
Title = "橙 汁 Orange",
Values = new ChartValues<ObservableValue> { new ObservableValue() },
DataLabels = true,
FontSize = 28
},
new PieSeries
{
Title = "苹果汁 Apple",
Values = new ChartValues<ObservableValue> { new ObservableValue() },
DataLabels = true,
FontSize = 28
},
new PieSeries
{
Title = "梨 汁 Pear",
Values = new ChartValues<ObservableValue> { new ObservableValue() },
DataLabels = true,
FontSize = 28
}
};
}
private void UpdateChartSeries()
{
OrangeOrderCount.Value = TodaysFinishedOrderList?.FindAll(o => o.PRODUCT_CODE == (int)ItemType.Orange).Count ?? 0;
AppleOrderCount.Value = TodaysFinishedOrderList?.FindAll(o => o.PRODUCT_CODE == (int)ItemType.Apple).Count ?? 0;
PearOrderCount.Value = TodaysFinishedOrderList?.FindAll(o => o.PRODUCT_CODE == (int)ItemType.Pear).Count ?? 0;
OrderCountSeries[0].Values[0] = OrangeOrderCount;
OrderCountSeries[1].Values[0] = AppleOrderCount;
OrderCountSeries[2].Values[0] = PearOrderCount;
}
优势:可动态更新数据,适合实时监控场景。
5、柱状图(Column Chart)
前台代码
xml
<lvc:CartesianChart Margin="20,75,20,15">
<lvc:CartesianChart.AxisX>
<lvc:Axis Style="{StaticResource FontChartAxis}"
FontSize="12"
Labels="{Binding Path=StorageLabels}"
Title="库位"
LabelsRotation="20">
<lvc:Axis.Separator>
<lvc:Separator Step="1" IsEnabled="False"/>
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisX>
<lvc:CartesianChart.AxisY>
<lvc:Axis Style="{StaticResource FontChartAxis}"
FontSize="12"
Title="百分比"
LabelFormatter="{Binding Path=AxisPercentage}">
<lvc:Axis.Separator>
<lvc:Separator Stroke="#33ffffff" StrokeDashArray="10"/>
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisY>
<lvc:CartesianChart.Series>
<lvc:ColumnSeries Style="{StaticResource FontColumnSeries}"
Values="{Binding Path=StoragePercentages}"
DataLabels="True"
LabelsPosition="Top"/>
</lvc:CartesianChart.Series>
<lvc:CartesianChart.ChartLegend>
<lvc:DefaultLegend BulletSize="12" Style="{StaticResource FontChartLegend}"/>
</lvc:CartesianChart.ChartLegend>
</lvc:CartesianChart>
后台代码
csharp
private Func<double, string> _axisPercentage;
private string[] _storageLabels;
private IChartValues _storagePercentages;
public Func<double, string> AxisPercentage { get => _axisPercentage; set { _axisPercentage = value; NotifyOfPropertyChange(() => AxisPercentage); } }
public string[] StorageLabels { get => _storageLabels; set { _storageLabels = value; NotifyOfPropertyChange(() => StorageLabels); } }
public IChartValues StoragePercentages { get => _storagePercentages; set { _storagePercentages = value; NotifyOfPropertyChange(() => StoragePercentages); } }
private void ShowStoragePercentageColumnChart()
{
StorageLabels = new[]
{
"单元一原料","单元一成品","单元二原料","单元二半成品",
"单元三原料","单元三半成品","单元四原料","单元四半成品"
};
AxisPercentage = val => val.ToString("P"); // 百分比格式化
StoragePercentages = new ChartValues<double> { 0.2, 0.5, 0.44, 0.88, 0.22, 0.6, 0.14, 0.09 };
}
6、折线图(Line Chart)
前台代码
xml
<lvc:CartesianChart Grid.Column="2" LegendLocation="Right" Margin="15,0">
<lvc:CartesianChart.AxisX>
<lvc:Axis Style="{StaticResource FontChartAxis}"
FontSize="12"
Labels="{Binding Path=XTimeLabels}"
Title="时间"
LabelsRotation="40">
<lvc:Axis.Separator>
<lvc:Separator Step="1" IsEnabled="False"/>
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisX>
<lvc:CartesianChart.AxisY>
<lvc:Axis Style="{StaticResource FontChartAxis}"
FontSize="12"
Title="百分比"
LabelFormatter="{Binding Path=YPercentageFormat}">
<lvc:Axis.Separator>
<lvc:Separator Stroke="#33ffffff" StrokeDashArray="10"/>
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisY>
<lvc:CartesianChart.Series>
<lvc:LineSeries Values="{Binding OccupancyRatesCell1}"
PointGeometrySize="2"
Stroke="#00f5ff"
Fill="#1100f5ff"
LineSmoothness="0"
Title="一单元"/>
<lvc:LineSeries Values="{Binding OccupancyRatesCell2}"
PointGeometrySize="2"
Stroke="#ccffcc"
Fill="#11ccffcc"
LineSmoothness="0"
Title="二单元"/>
<lvc:LineSeries Values="{Binding OccupancyRatesCell3}"
PointGeometrySize="2"
Stroke="#333399"
Fill="#11333399"
LineSmoothness="0"
Title="三单元"/>
<lvc:LineSeries Values="{Binding OccupancyRatesCell4}"
PointGeometrySize="2"
Stroke="#9966cc"
Fill="#119966cc"
LineSmoothness="0"
Title="四单元"/>
</lvc:CartesianChart.Series>
<lvc:CartesianChart.ChartLegend>
<lvc:DefaultLegend BulletSize="12" Style="{StaticResource FontChartLegend}"/>
</lvc:CartesianChart.ChartLegend>
</lvc:CartesianChart>
后台代码
csharp
private string[] _xTimeLabels;
private Func<double, string> _yPercentageFormat;
private ChartValues<double> _occupancyRatesCell1, _occupancyRatesCell2,
_occupancyRatesCell3, _occupancyRatesCell4;
public string[] XTimeLabels { get => _xTimeLabels; set { _xTimeLabels = value; NotifyOfPropertyChange(() => XTimeLabels); } }
public Func<double, string> YPercentageFormat { get => _yPercentageFormat; set { _yPercentageFormat = value; NotifyOfPropertyChange(() => YPercentageFormat); } }
public ChartValues<double> OccupancyRatesCell1 { get => _occupancyRatesCell1; set { _occupancyRatesCell1 = value; NotifyOfPropertyChange(() => OccupancyRatesCell1); } }
public ChartValues<double> OccupancyRatesCell2 { get => _occupancyRatesCell2; set { _occupancyRatesCell2 = value; NotifyOfPropertyChange(() => OccupancyRatesCell2); } }
public ChartValues<double> OccupancyRatesCell3 { get => _occupancyRatesCell3; set { _occupancyRatesCell3 = value; NotifyOfPropertyChange(() => OccupancyRatesCell3); } }
public ChartValues<double> OccupancyRatesCell4 { get => _occupancyRatesCell4; set { _occupancyRatesCell4 = value; NotifyOfPropertyChange(() => OccupancyRatesCell4); } }
private void InitOccupancyRate()
{
YPercentageFormat = value => value.ToString("P0"); // 整数百分比
XTimeLabels = new[] { "08:00", "09:00", "10:00", "11:00", "12:00",
"13:00", "14:00", "15:00", "16:00", "17:00" };
OccupancyRatesCell1 = new ChartValues<double> { 0.75, 0.87, 0.82, 0.69, 0.73,
0.71, 0.80, 0.85, 0.88, 0.79 };
OccupancyRatesCell2 = new ChartValues<double> { 0.84, 0.77, 0.66, 0.74, 0.83,
0.79, 0.75, 0.79, 0.84, 0.86 };
OccupancyRatesCell3 = new ChartValues<double> { 0.87, 0.85, 0.77, 0.88, 0.69,
0.82, 0.77, 0.78, 0.73, 0.84 };
OccupancyRatesCell4 = new ChartValues<double> { 0.81, 0.76, 0.78, 0.80, 0.64,
0.85, 0.83, 0.68, 0.78, 0.82 };
}
7、样式定义(Styles.xaml)
统一图表字体、颜色等视觉风格:
xml
<!-- LiveCharts 文字样式 -->
<Style x:Key="FontChartAxis" TargetType="{x:Type lvc:Axis}">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="FontFamily" Value="Microsoft Yahei"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Foreground" Value="White"/>
</Style>
<Style x:Key="FontStackedColumnSeries" TargetType="{x:Type lvc:StackedColumnSeries}">
<Setter Property="FontFamily" Value="Microsoft Yahei"/>
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="White"/>
</Style>
<Style x:Key="FontColumnSeries" TargetType="{x:Type lvc:ColumnSeries}">
<Setter Property="FontFamily" Value="Microsoft Yahei"/>
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="White"/>
</Style>
<Style x:Key="FontChartLegend" TargetType="{x:Type lvc:DefaultLegend}">
<Setter Property="FontFamily" Value="Microsoft Yahei"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="White"/>
</Style>
<Style x:Key="FontRowSeries" TargetType="{x:Type lvc:RowSeries}">
<Setter Property="FontFamily" Value="Microsoft Yahei"/>
<Setter Property="FontSize" Value="9"/>
<Setter Property="Foreground" Value="White"/>
</Style>
<Style x:Key="FontPieSeries" TargetType="{x:Type lvc:PieSeries}">
<Setter Property="FontFamily" Value="Microsoft Yahei"/>
<Setter Property="FontSize" Value="24"/>
<Setter Property="Foreground" Value="White"/>
</Style>
将此资源字典合并到 App.xaml 或用户控件中以全局使用。
总结
LiveCharts 提供了简洁的 API 和强大的数据绑定能力,结合 MVVM 模式可轻松实现动态、响应式的数据可视化。以上示例涵盖了工业、仓储、订单统计等常见业务场景,开发者可根据需求灵活调整样式与数据逻辑。
提示
-
使用
ObservableValue可实现数据变更自动刷新图表。 -
支持鼠标悬停提示、动画过渡、缩放等功能。
-
推荐使用深色背景搭配高对比度颜色提升可读性。
如需更多高级功能(如实时数据流、自定义几何图形),可查阅 LiveCharts 官方文档。
最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。
也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!
优秀是一种习惯,欢迎大家留言学习!
来源:cnblogs.com/gnielee/archive/2010/08/02/wpf-cpu-usage.html