WPF MVVM LiveCharts如何显示X轴标签?
WPF MVVM LiveCharts how to show X axis Label?
我很难在我的笛卡尔条形图中显示一些简单的标签,我阅读了很多,但似乎没有什么对我有用。我在我的项目中使用 MVVM 模式,所以这是我目前的代码..
VIEW
<lvc:CartesianChart Grid.Row="2" Series="{Binding ChartDataSets}">
<lvc:CartesianChart.AxisX>
<lvc:Axis LabelsRotation="20" Labels="{Binding ColumnLabels}" Position="RightTop" >
<lvc:Axis.Separator >
<lvc:Separator Step="1"></lvc:Separator>
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisX>
<lvc:CartesianChart.AxisY>
<lvc:Axis LabelFormatter="{Binding Formatter}" Position="RightTop"></lvc:Axis>
</lvc:CartesianChart.AxisY>
</lvc:CartesianChart>
DataModel
class 数据模型:INotifyPropertyChanged
{
私人双重价值;
public 双值
{
得到 => this.value;
放
{
this.value = 值;
OnPropertyChanged();
}
}
private string label;
public string Label
{
get => this.label;
set
{
this.label = value;
OnPropertyChanged("Label");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
ViewModel
class BackupStatsViewModel : INotifyPropertyChanged
{
ChartValues<DataModel> values = new ChartValues<DataModel>();
public SeriesCollection ChartDataSets { get; set; }
public ObservableCollection<string> ColumnLabels { get; set; }
public class ErrorPrt
{
public ErrorPrt(){
prtName = string.Empty;
Count = -1;
}
public string prtName { get; set; }
public int Count { get; set; }
}
public BackupStatsViewModel()
{
InitializeBarChartData();
}
private void InitializeBarChartData()
{
this.ColumnLabels = new ObservableCollection<string>(values.Select(dataModel => dataModel.Label));
var dataMapper = new CartesianMapper<DataModel>()
.Y(dataModel => dataModel.Value)
.Fill(dataModel => dataModel.Value > 15.0 ? Brushes.Red : Brushes.Green);
this.ChartDataSets = new SeriesCollection
{
new ColumnSeries
{
Values = values,
Configuration = dataMapper,
DataLabels = true
}
};
}
public ErrorPrt[] PrtCount(List<DataRow> rows)
{
IEnumerable<IGrouping<string, DataRow>> grouped = rows.GroupBy(s => s.Field<string>(2));
ErrorPrt[] err = new ErrorPrt[grouped.Count()];
//Omitted code for sake of brevity
ErrorPrt[] arr = err.Where(c => c != null).ToArray();
for (int i = 0; i < arr.Count(); i++)
values.Add(new DataModel() { Label = $"PRT {arr[i].prtName}", Value = arr[i].Count });
return arr;
}
}
但是如您所见,X 轴上没有显示任何标签。真的不知道如何绕过这个问题才能继续我的工作。请问谁能告诉我正确的方法吗?
您的流程看起来有问题:
您首先通过调用 InitializeBarChartData()
从构造函数初始化图表数据,这也会初始化 ColumnLabels
集合。 然后 创建基础 ErrorPtr
项,它们是列标签数据的提供者。
结果是 ColumnLabels
属性 为空 => 不会显示任何标签。
因为您将新的 ErrorPtr
项添加到 values
字段并且该字段的类型为 ChartValues
并且此集合实现了 INotifyCollectionChanged
,图表将反映这些变化。你在这里很幸运。
但是因为您在创建 ErrorPtr
项目后从未更新 ColumnLabels
属性,最初(在 调用 InitializeBarChartData
来自构造函数)空 ColumnLabels
集合保持为空。
解决方案 1
修复数据模型初始化的流程并调用 InitializeBarChartData
after PrtCount
:
public ErrorPrt[] PrtCount(List<DataRow> rows)
{
IEnumerable<IGrouping<string, DataRow>> grouped = rows.GroupBy(s => s.Field<string>(2));
ErrorPrt[] err = new ErrorPrt[grouped.Count()];
//Omitted code for sake of brevity
ErrorPrt[] arr = err.Where(c => c != null).ToArray();
for (int i = 0; i < arr.Count(); i++)
this.values.Add(new DataModel() { Label = $"PRT {arr[i].prtName}", Value = arr[i].Count });
// Initialize the chat models.
// NOW the label data (the ErrorPrt.prtName) is generated
// and ready to be extracted from the ErrorPrt instances
InitializeBarChartData();
return arr;
}
方案二(推荐)
由于所有涉及的集合都实现了 INotifyCollectionChanged
,您可以在新数据到达时动态更新每个集合。您不需要一遍又一遍地初始化完整的图表数据,如 SeriesCollection
和 Mapper
或标签格式化程序(如 解决方案 1 - 在case PrtCount
会被调用不止一次)。
您可以继续从构造函数调用一次 InitializeBarChartData
,就像您当前正在做的那样。
不仅要更新 values
字段,还要更新 ColumnLabels
属性:
public ErrorPrt[] PrtCount(List<DataRow> rows)
{
IEnumerable<IGrouping<string, DataRow>> grouped = rows.GroupBy(s => s.Field<string>(2));
ErrorPrt[] err = new ErrorPrt[grouped.Count()];
//Omitted code for sake of brevity
ErrorPrt[] arr = err.Where(c => c != null).ToArray();
for (int i = 0; i < arr.Count(); i++)
{
var newDataModel = new DataModel() { Label = $"PRT {arr[i].prtName}", Value = arr[i].Count };
// Here you update the column values
// and add the new items to the existing items of previous calls
this.values.Add(newDataModel);
// Also update the labels whenever new column data has arrived
this.ColumnLabels.Add(newDataModel.Label);
}
return arr;
}
我很难在我的笛卡尔条形图中显示一些简单的标签,我阅读了很多,但似乎没有什么对我有用。我在我的项目中使用 MVVM 模式,所以这是我目前的代码..
VIEW
<lvc:CartesianChart Grid.Row="2" Series="{Binding ChartDataSets}">
<lvc:CartesianChart.AxisX>
<lvc:Axis LabelsRotation="20" Labels="{Binding ColumnLabels}" Position="RightTop" >
<lvc:Axis.Separator >
<lvc:Separator Step="1"></lvc:Separator>
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisX>
<lvc:CartesianChart.AxisY>
<lvc:Axis LabelFormatter="{Binding Formatter}" Position="RightTop"></lvc:Axis>
</lvc:CartesianChart.AxisY>
</lvc:CartesianChart>
DataModel
class 数据模型:INotifyPropertyChanged { 私人双重价值; public 双值 { 得到 => this.value; 放 { this.value = 值; OnPropertyChanged(); } }
private string label;
public string Label
{
get => this.label;
set
{
this.label = value;
OnPropertyChanged("Label");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
ViewModel
class BackupStatsViewModel : INotifyPropertyChanged
{
ChartValues<DataModel> values = new ChartValues<DataModel>();
public SeriesCollection ChartDataSets { get; set; }
public ObservableCollection<string> ColumnLabels { get; set; }
public class ErrorPrt
{
public ErrorPrt(){
prtName = string.Empty;
Count = -1;
}
public string prtName { get; set; }
public int Count { get; set; }
}
public BackupStatsViewModel()
{
InitializeBarChartData();
}
private void InitializeBarChartData()
{
this.ColumnLabels = new ObservableCollection<string>(values.Select(dataModel => dataModel.Label));
var dataMapper = new CartesianMapper<DataModel>()
.Y(dataModel => dataModel.Value)
.Fill(dataModel => dataModel.Value > 15.0 ? Brushes.Red : Brushes.Green);
this.ChartDataSets = new SeriesCollection
{
new ColumnSeries
{
Values = values,
Configuration = dataMapper,
DataLabels = true
}
};
}
public ErrorPrt[] PrtCount(List<DataRow> rows)
{
IEnumerable<IGrouping<string, DataRow>> grouped = rows.GroupBy(s => s.Field<string>(2));
ErrorPrt[] err = new ErrorPrt[grouped.Count()];
//Omitted code for sake of brevity
ErrorPrt[] arr = err.Where(c => c != null).ToArray();
for (int i = 0; i < arr.Count(); i++)
values.Add(new DataModel() { Label = $"PRT {arr[i].prtName}", Value = arr[i].Count });
return arr;
}
}
但是如您所见,X 轴上没有显示任何标签。真的不知道如何绕过这个问题才能继续我的工作。请问谁能告诉我正确的方法吗?
您的流程看起来有问题:
您首先通过调用 InitializeBarChartData()
从构造函数初始化图表数据,这也会初始化 ColumnLabels
集合。 然后 创建基础 ErrorPtr
项,它们是列标签数据的提供者。
结果是 ColumnLabels
属性 为空 => 不会显示任何标签。
因为您将新的 ErrorPtr
项添加到 values
字段并且该字段的类型为 ChartValues
并且此集合实现了 INotifyCollectionChanged
,图表将反映这些变化。你在这里很幸运。
但是因为您在创建 ErrorPtr
项目后从未更新 ColumnLabels
属性,最初(在 调用 InitializeBarChartData
来自构造函数)空 ColumnLabels
集合保持为空。
解决方案 1
修复数据模型初始化的流程并调用 InitializeBarChartData
after PrtCount
:
public ErrorPrt[] PrtCount(List<DataRow> rows)
{
IEnumerable<IGrouping<string, DataRow>> grouped = rows.GroupBy(s => s.Field<string>(2));
ErrorPrt[] err = new ErrorPrt[grouped.Count()];
//Omitted code for sake of brevity
ErrorPrt[] arr = err.Where(c => c != null).ToArray();
for (int i = 0; i < arr.Count(); i++)
this.values.Add(new DataModel() { Label = $"PRT {arr[i].prtName}", Value = arr[i].Count });
// Initialize the chat models.
// NOW the label data (the ErrorPrt.prtName) is generated
// and ready to be extracted from the ErrorPrt instances
InitializeBarChartData();
return arr;
}
方案二(推荐)
由于所有涉及的集合都实现了 INotifyCollectionChanged
,您可以在新数据到达时动态更新每个集合。您不需要一遍又一遍地初始化完整的图表数据,如 SeriesCollection
和 Mapper
或标签格式化程序(如 解决方案 1 - 在case PrtCount
会被调用不止一次)。
您可以继续从构造函数调用一次 InitializeBarChartData
,就像您当前正在做的那样。
不仅要更新 values
字段,还要更新 ColumnLabels
属性:
public ErrorPrt[] PrtCount(List<DataRow> rows)
{
IEnumerable<IGrouping<string, DataRow>> grouped = rows.GroupBy(s => s.Field<string>(2));
ErrorPrt[] err = new ErrorPrt[grouped.Count()];
//Omitted code for sake of brevity
ErrorPrt[] arr = err.Where(c => c != null).ToArray();
for (int i = 0; i < arr.Count(); i++)
{
var newDataModel = new DataModel() { Label = $"PRT {arr[i].prtName}", Value = arr[i].Count };
// Here you update the column values
// and add the new items to the existing items of previous calls
this.values.Add(newDataModel);
// Also update the labels whenever new column data has arrived
this.ColumnLabels.Add(newDataModel.Label);
}
return arr;
}