Xamarin.Forms SFChart加载API数据后折线图DateTime轴时间显示错误修复
Xamarin.Forms SFChart折线图DateTime轴加载数据后标签重复异常问题
问题描述
在Xamarin.Forms中使用SFChart折线图加载API响应数据时,折线图的DateTime主轴(X轴)出现时间显示错误。
当前实现使用SFChart折线图展示时序数据:
- X轴为时间轴
- Y轴为对应数值轴
- 预期展示24小时连续时序数据,时间、数值字段均从API响应中提取
未加载数据时,DateTime轴显示正常:已为DateTime主轴设置IntervalType属性为Hours、Interval属性为1,预期按1小时间隔展示时间标签,未加载数据时效果如下:
加载API返回的数据后,DateTime轴时间标签出现异常重复,固定重复显示12AM、4PM、8AM等值,无法按预期生成连续的小时级时间刻度,异常效果如下:
现有实现代码
页面XAML代码
<Frame HasShadow="False" x:Name="outframe" CornerRadius="{OnIdiom Phone=15,Tablet=25}" Padding="0" OutlineColor="#ffffff" BackgroundColor="#4A4541" WidthRequest="{OnIdiom Phone=320,Tablet=600}" HeightRequest="{OnIdiom Phone=450,Tablet=475}" VerticalOptions="Center" HorizontalOptions="Center" IsClippedToBounds="True"> <StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" BackgroundColor="#4A4541"> <Label Text="GRAPH" FontFamily="{StaticResource PrimaryFontBold}" TextColor="White" VerticalTextAlignment="Center" Margin="0,50,0,0" HorizontalTextAlignment="Center" FontSize="{OnIdiom Phone=16,Tablet=22}" HorizontalOptions="Center" /> <sfcharts:SfChart HeightRequest="200" WidthRequest="300" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" BackgroundColor="#4A4541" AreaBorderColor="White" AreaBackgroundColor="#4A4541"> <sfcharts:SfChart.PrimaryAxis> <sfcharts:DateTimeAxis IntervalType="Hours" Interval="1" LabelRotationAngle="90" > <sfcharts:DateTimeAxis.LabelStyle> <sfcharts:ChartAxisLabelStyle LabelFormat = "hh:mm tt" TextColor="#FDDFBD"> </sfcharts:ChartAxisLabelStyle> </sfcharts:DateTimeAxis.LabelStyle> </sfcharts:DateTimeAxis> </sfcharts:SfChart.PrimaryAxis> <sfcharts:SfChart.SecondaryAxis> <sfcharts:NumericalAxis Minimum="0" Maximum="60" Interval="10" > <sfcharts:NumericalAxis.LabelStyle> <sfcharts:ChartAxisLabelStyle TextColor="White"> </sfcharts:ChartAxisLabelStyle> </sfcharts:NumericalAxis.LabelStyle> <sfcharts:NumericalAxis.MajorGridLineStyle> <sfcharts:ChartLineStyle StrokeColor="#bae1f2"/> </sfcharts:NumericalAxis.MajorGridLineStyle> </sfcharts:NumericalAxis> </sfcharts:SfChart.SecondaryAxis> <sfcharts:StackingLineSeries x:Name="MyLineChart" XBindingPath="Key" YBindingPath="Value" ItemsSource="{Binding LineData}" ListenPropertyChange="True" StrokeWidth="1" Color="#FDDFBD" > <sfcharts:StackingLineSeries.DataMarker> <sfcharts:ChartDataMarker MarkerWidth="2" MarkerHeight="2" ShowLabel="False" ShowMarker="true" MarkerBorderColor="#bae1f2" MarkerBorderWidth="2" MarkerColor="White"/> </sfcharts:StackingLineSeries.DataMarker> </sfcharts:StackingLineSeries> </sfcharts:SfChart> </StackLayout> </Frame>
页面后台代码
RViewModel rViewModel; public RRGraph() { InitializeComponent(); rViewModel = new RViewModel(); BindingContext = rViewModel; }
数据模型代码
public class ChartData { public string name { get; set; } public ObservableCollection<LineChartData> DataPoints { get; set; } } public class LineChartData:INotifyPropertyChanged { public LineChartData(string key, double value) { Value = value; Key = key; } private double value; public double Value { get { return value; } set { this.value = value; RaisePropertyChanged("Value"); } } private string key; public string Key { get { return key; } set { DateTime dt = DateTime.Parse(value); value = dt.ToString("hh:mm tt"); key = value; RaisePropertyChanged("Key"); } } public event PropertyChangedEventHandler PropertyChanged; void RaisePropertyChanged(string name) { if (PropertyChanged != null) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } }
ViewModel代码
public class RViewModel:INotifyPropertyChanged { public ChartData ChartData { get; set; } private ObservableCollection<LineChartData> lineData; public ObservableCollection<LineChartData> LineData { get { return lineData; } set { lineData = value; RaisePropertyChanged(nameof(LineData)); } } public event PropertyChangedEventHandler PropertyChanged; void RaisePropertyChanged(string name) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } public RViewModel(string roomId) { LoadData(); } public async void LoadData() { try { //API调用逻辑 ChartData = await AppClass.DataManager.GetRR(); LineData = ChartData.DataPoints; } catch (Exception ex) { Crashes.TrackError(ex); } } }
问题根因
核心问题出在数据模型的X轴字段定义上:
- XAML中配置的主轴是
DateTimeAxis,这类轴要求绑定的X值必须是DateTime类型,才能按照时间规则自动计算等间隔刻度。 - 现有代码里X轴绑定的
Key属性是字符串类型,set逻辑中还把解析出的DateTime值重新转成了hh:mm tt格式的时间字符串。图表无法将字符串识别为连续的时间维度值,只能把每个字符串当做独立分类处理,最终导致刻度生成逻辑混乱、标签重复错位。
解决方案
- 修改
LineChartData模型,将X轴绑定字段改为DateTime类型,不要存储格式化后的字符串:
public class LineChartData:INotifyPropertyChanged { public LineChartData(DateTime key, double value) { Value = value; Key = key; } private double value; public double Value { get { return value; } set { this.value = value; RaisePropertyChanged("Value"); } } private DateTime key; // X轴绑定字段改为DateTime类型 public DateTime Key { get { return key; } set { key = value; RaisePropertyChanged("Key"); } } public event PropertyChangedEventHandler PropertyChanged; void RaisePropertyChanged(string name) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } }
- 在API数据解析环节,将接口返回的时间字符串统一转为
DateTime类型再赋值给Key属性,不要提前转成格式化字符串,轴的显示格式完全交给XAML里配置的LabelFormat = "hh:mm tt"处理即可。 - 加载完数据后对
LineData按Key时间做一次升序排序,排查是否存在时间戳错乱、大量重复时间点的情况,避免刻度计算异常。
内容的提问来源于stack exchange,提问作者BSB
相关产品推荐
相关产品推荐

