我正在尝试使用 SfCartesianChart(版本 22.2.12)在 dotnet maui 中显示动态数量的系列。
图表中的所有数据都存在于 ViewModel 中,如下所示:
public class ChartPageViewModel : BaseViewModel, IChartPageViewModel
{
//Data are loaded asynchronously after the page load
//after setting the data the PropertyChangedEvent is fired
public ObservableCollection<IChartSeriesViewModel> DataSeries { get; set; }
}
public class ChartSeriesViewModel : IChartSeriesViewModel
{
public string Title { get; set; }
public IList<IChartPointViewModel> Data { get; set; }
}
public class ChartPointViewModel : IChartPointViewModel
{
public DateTime Date { get; set; }
public decimal Value { get; set; }
}
使用值转换器将数据与系列属性绑定:
<chart:SfCartesianChart Series="{Binding DataSeries, Converter={StaticResource DataSeriesConverter}}">
<chart:SfCartesianChart.XAxes>
<chart:CategoryAxis />
</chart:SfCartesianChart.XAxes>
<chart:SfCartesianChart.YAxes>
<chart:NumericalAxis />
</chart:SfCartesianChart.YAxes>
</chart:SfCartesianChart>
值转换器(IList 到 ChartSeriesCollection)
public class SfCartesianChartDataSeriesConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is IList<IChartSeriesViewModel> chartSeries)
{
ChartSeriesCollection series = new ChartSeriesCollection();
foreach (var i in chartSeries)
{
series.Add(new FastLineSeries()
{
ItemsSource = i.Data,
XBindingPath = nameof(IChartPointViewModel.Date),
YBindingPath = nameof(IChartPointViewModel.Value),
});
}
return series;
}
return null;
}
不幸的是,数据仅在重绘视图时显示/绘制(例如,调整窗口大小)。
PropertyChangedEvent 似乎工作正常,因为当我在 xaml 中添加一系列数据时,数据会在 PropertyChangedEvent 之后立即显示。
<chart:SfCartesianChart>
<chart:SfCartesianChart.XAxes>
<chart:CategoryAxis />
</chart:SfCartesianChart.XAxes>
<chart:SfCartesianChart.YAxes>
<chart:NumericalAxis />
</chart:SfCartesianChart.YAxes>
<chart:FastLineSeries
ItemsSource="{Binding DataSeries[0].Data}"
XBindingPath="Date"
YBindingPath="Value" />
</chart:SfCartesianChart>
但这不是创建动态数量系列的方法。
如何强制“重画”? 或者这种情况应该如何绑定?
已根据您的输入准备了样本。这一要求已通过扩展 CartesianChart 来实现。下面附上示例供参考。
公共类 CartesianExt :SfCartesianChart
{
public static readonly BindableProperty SeriesCollectionProperty = BindableProperty.Create("SeriesCollection", typeof(ObservableCollection<IChartSeriesViewModel>), typeof(CartesianExt), null, BindingMode.Default, null, OnSeriesPropertyChanged);
public ObservableCollection<IChartSeriesViewModel> SeriesCollection
{
get
{
return (ObservableCollection<IChartSeriesViewModel>)GetValue(SeriesCollectionProperty);
}
set { SetValue(SeriesCollectionProperty, value);}
}
private static void OnSeriesPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
(bindable as CartesianExt).GenerateSeries(newValue);
}
private void GenerateSeries(object newValue)
{
if(newValue is ObservableCollection<IChartSeriesViewModel> collection)
{
if (newValue is INotifyCollectionChanged)
(newValue as INotifyCollectionChanged).CollectionChanged += DataPoint_CollectionChanged;
foreach(var item in collection)
{
CreateSeries(item);
}
}
}
private void CreateSeries(IChartSeriesViewModel item)
{
FastLineSeries series = new FastLineSeries()
{
ItemsSource = item.LiveData,
XBindingPath = nameof(IChartPointViewModel.Date),
YBindingPath = nameof(IChartPointViewModel.Value),
};
Series.Add(series);
}
private void DataPoint_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
CreateSeries(e.NewItems[0] as IChartSeriesViewModel);
break;
case NotifyCollectionChangedAction.Remove:
Series.RemoveAt(e.OldStartingIndex);
break;
}
}
}
公共 ChartSeriesViewModel()
{
LiveData = new ObservableCollection<IChartPointViewModel>();
for (int i = 0; i < 100; i++)
{
LiveData.Add(new ChartPointViewModel() { Date = new DateTime(2005, 04, 02).AddMonths(i), Value = new Random().Next(0, 1000) });
}
}
公共类 ChartPageViewModel:ChartSeriesViewModel
{
public ObservableCollection<IChartSeriesViewModel> DataSeries { get; set; }
public ChartPageViewModel()
{
DataSeries=new ObservableCollection<IChartSeriesViewModel>();
DataSeries.Add(new ChartSeriesViewModel());
}
}
<local:CartesianExt SeriesCollection="{Binding DataSeries}" x:Name="Chart" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<chart:SfCartesianChart.XAxes>
<chart:CategoryAxis/>
</chart:SfCartesianChart.XAxes>
<chart:SfCartesianChart.YAxes>
<chart:NumericalAxis/>
</chart:SfCartesianChart.YAxes>
</local:CartesianExt>
<Button Text="DynamicList" Clicked="Button_Clicked"></Button>
</VerticalStackLayout>
private void Button_Clicked(对象发送者,EventArgs e)
{
chartPageViewModel.DataSeries.Add(new ChartSeriesViewModel());
}