Search code examples
c#wpfdata-bindingbindinglivecharts

WPF with LiveCharts add series with DataBinding at runtime


I have a project where I have a charting area. I have choosen LiveCharts ( http://lvcharts.net ) for that matter.

So far so good, the charting works with databinding when added in xaml: enter image description here

<UserControl x:Class="Work_Task_Planner_Sheduler.Views.TeamTaskProgressChartView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Work_Task_Planner_Sheduler.Views"
             xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <lvc:CartesianChart x:Name="TeamTaskProgressChartComponent">
            <lvc:CartesianChart.Series>
                <lvc:LineSeries Title="Julian" Values="{Binding Taskprogress_julian}" />
            </lvc:CartesianChart.Series>
            <lvc:CartesianChart.AxisX>
                <lvc:Axis Title="Time"></lvc:Axis>
            </lvc:CartesianChart.AxisX>
            <lvc:CartesianChart.AxisY>
                <lvc:Axis Title="TaskProgress"></lvc:Axis>
            </lvc:CartesianChart.AxisY>
        </lvc:CartesianChart>
    </Grid>
</UserControl>

The issue is: The Line series is hardcoded in xaml. Who knows if the team gets bigger/smaller over time or the team members change. Therefore I want to create the line series at runtime.

This is what I have so far, unfortunately the series stays empty:

CartesianChart chart = this.TeamTaskProgressChartComponent;
foreach(string user in TeamMembers)
{
    LineSeries lineseries = new LineSeries();
    string title = user.Split('.')[0];
    lineseries.Title = title;
    Binding databinding = new Binding();
    databinding.Source =
    Datarefresh.mainWindow.mainViewModel.TeamTaskProgressChartViewModel.TaskProgressCounts;
    DependencyProperty LineSeriesProperty = DependencyProperty.Register(title+"Property", typeof(int), typeof(LineSeries), new PropertyMetadata(0));
    lineseries.SetBinding(LineSeriesProperty, databinding);
    chart.series.Add(lineseries);
}

Solution

  • Actually the Process is quite Simple:

    1. Create a Series collation. IMPORTANT: The series collection must be initialized in the constructor so that it is ready when the chart loads:

      public class TeamTicketResolveChartViewModel
      {
          public SeriesCollection ChartSeries { get; set; }
          public string[] TicketResolveLabels { get; set; }
      
          public TeamTicketResolveChartViewModel()
          {
              ChartSeries = new SeriesCollection();
              foreach (string user in TeamMembers.ServiceDesk)
              {
                  LineSeries lineseries = new LineSeries();
                  string title = user.Split('.')[0];
                  lineseries.Title = title;
                  ChartSeries.Add(lineseries);
              }
          }
          // other functions
      }
      
    2. In xaml, bind the chart to the series Collection:

      <lvc:CartesianChart x:Name="TeamTicketResolveChartComponent" Series="{Binding ChartSeries}" />
      
    3. Now updating the Chart Data will work as intended:

      public void LoadChartData2(List<List<(DateTime time, int resolved)>> input)
      {
          for (int i = 0; i < input.Count; i++)
          {
              ChartSeries[i].Values = new ChartValues<int>(input[i].Select(c => c.resolved));
          }
      
          DateTime[] dates = input[0].Select(c => c.time).ToArray();
          List<string> labels = new List<string>();
          foreach (DateTime time in dates) labels.Add(time.ToString("HH:mm:ss"));
          TicketResolveLabels = labels.ToArray();
      }
      public void AddChartPoint(List<List<(DateTime time, int resolved)>> input)
      {
          // Chartseries[i].values.Add()
      }