从数据表动态更新 LiveCharts

Update LiveCharts from datatable dynamically

我已经阅读文档好几天了,但无论我尝试什么,我都无法正常工作。我有 Basic Row 图表,并希望以图表形式显示所花费的时间。我的栏标题和值不断变化(添加了更多项目)。我可以使用当前代码添加栏,但无法为每个添加的栏添加标题。只有第一个标题/第一个栏标题可见,所有其他/后面的标题不可见。

如何正确添加title和value? (我已经熟悉文档https://lvcharts.net/App/examples/v1/wf/Basic%20Row

这是我的代码(你可以从注释掉的部分看到已经尝试过的部分):

    public static SeriesCollection SeriesCollection { get; set; }
    public static string[] Labels { get; set; }
    public static List<string> LabelsList { get; set; }
    public static Func<double, string> Formatter { get; set; }

    public AppUsageBarGraph()
    {
        InitializeComponent();

        LabelsList = new List<string>();

        SeriesCollection = new SeriesCollection
        {
            new RowSeries
            {
                Values = new ChartValues<double> { },
                DataLabels = true
            }
        };

        DataContext = this;
    }

    public static void UpdateChart()
    {
        SeriesCollection[0].Values.Clear();
        LabelsList.Clear();

        //Labels = MainProcess.ActivityLogGrouped.Rows.Cast<DataRow>().Select(row => row["Window Title"].ToString()).ToArray();

        foreach (DataRow row in MainProcess.ActivityLogGrouped.Rows)
        {
            SeriesCollection[0].Values.Add(Convert.ToDouble(row["Time Spent"]));
            //SeriesCollection[0]. = row["Time Spent"].ToString());
            LabelsList.Add(row["Window Title"].ToString());
        }

        //MessageBox.Show(Labels[0].ToString());

        Labels = LabelsList.ToArray(); 


        //foreach (var item in Labels)
        //{
        //    MessageBox.Show(item);
        //}

        //Labels = new[]
        //        {
        //              "Shea Ferriera",
        //              "Maurita Powel",
        //              "Scottie Brogdon",
        //              "Teresa Kerman",
        //              "Nell Venuti",
        //              "Anibal Brothers",
        //              "Anderson Dillman"
        //           };

        //Formatter = value => value.ToString("N");
    }

关键是使用 ObservableCollection<string> 而不是 string[]

我也推荐使用一个模型来封装实际的图表数据点。为此我引入了classDataModel

以下示例演示如何将值和标签动态绑定到图表。我应该说,使一切public static是一个非常难闻的代码设计。

MainWindow.xaml

<Window>
  <Window.DataContext>
    <ViewModel />
  </Window.DataContext>

  <wpf:CartesianChart Height="500">
    <CartesianChart.Series>
      <RowSeries Values="{Binding ChartModel.RowSeries}"
                 Configuration="{Binding ChartModel.RowSeriesConfiguration}"/>
    </CartesianChart.Series>
    <CartesianChart.AxisY>
      <Axis Labels="{Binding ChartModel.RowSeriesLabels}" />
    </CartesianChart.AxisY>
  </CartesianChart>
</Window>

ViewModel.cs

public class ViewModel : INotifyPropertyChanged
{
  public ViewModel()
  {
    this.ChartModel = new ChartModel();
  }

  public void UpdateChart()
  {
    foreach (DataRow row in MainProcess.ActivityLogGrouped.Rows)
    {
      if (double.TryParse(row["Time Spent"], out double value)
      {
        string label = row["Window Title"];
        var newDataModel = new DataModel(value, label);

        this.ChartModel.RowSeries.Add(newDataModel);            
        this.ChartModel.RowSeriesLabels.Add(newDataModel.Label);
      }
    }
  }

  public ChartModel ChartModel { get; set; }

  public event PropertyChangedEventHandler PropertyChanged;
  protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
  {
    this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  }
}

ChartModel.cs

public class ChartModel : INotifyPropertyChanged
{
  public ChartModel()
  {
    // Initialize chart
    this.RowSeries = new ChartValues<DataModel>()
    {
      new DataModel(20, "Shea Ferriera"),
      new DataModel(100, "Maurita Powel"),
      new DataModel(60, "Scottie Brogdon"),
    };

    // Create labels
    this.RowSeriesLabels = new ObservableCollection<string>();
    foreach (DataModel dataModel in this.RowSeries)
    {
      this.RowSeriesLabels.Add("dataModel.Label");
    }

    // DatModel to value mapping
    this.RowSeriesConfiguration = new CartesianMapper<DataModel>()
      .X(dataModel => dataModel.Value);
  }

  public CartesianMapper<DataModel> RowSeriesConfiguration { get; set; }
  public ChartValues<DataModel> RowSeries { get; set; }
  public ObservableCollection<string> RowSeriesLabels { get; set; }

  public event PropertyChangedEventHandler PropertyChanged;
  protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
  {
    this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  }
}

DataModel.cs

public class DataModel
{
  public DataModel(double value, string label)
  {
    this.Value = value;
    this.Label = label;
  }

  public double Value { get; set; }
  public string Label { get; set; }
}