I am working on an executive dashboard that should be able to have any number of charts each with any number of series. I am using the WPF Toolkit.
The first problem I had was binding multiple series to a chart. I found Beat Kiener's excellent blogpost on binding multiple series to a chart which worked great until I put it in an items control, which I have to do to meet my "any number of charts" requirement.
It seems to me that the below code should work, but it does not. Can anyone explain why the below code does not work, or offer another way to do it using MVVM?
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public ChartData ChartData { get; set; }
public List<ChartData> ChartDataList { get; set; }
public MainWindow()
{
var dataSeries = new Dictionary<string, int>();
dataSeries.Add("Jan", 5);
dataSeries.Add("Feb", 7);
dataSeries.Add("Mar", 3);
ChartData = new ChartData();
ChartData.Title = "Chart Title";
ChartData.DataSeriesList = new List<Dictionary<string, int>>();
ChartData.DataSeriesList.Add(dataSeries);
ChartDataList = new List<ChartData>();
ChartDataList.Add(ChartData);
InitializeComponent();
this.DataContext = this;
}
}
public class ChartData
{
public string Title { get; set; }
public List<Dictionary<string, int>> DataSeriesList { get; set; }
}
MainWindow.xaml
<UniformGrid
Rows="1">
<!-- These charts do not work -->
<ItemsControl
x:Name="itemsControl"
ItemsSource="{Binding ChartDataList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:MultiChart
Title="{Binding Title}"
SeriesSource="{Binding DataSeriesList}">
<local:MultiChart.SeriesTemplate>
<DataTemplate >
<chartingToolkit:ColumnSeries
Title="Series Title"
ItemsSource="{Binding}"
IndependentValueBinding="{Binding Key}"
DependentValueBinding="{Binding Value}"/>
</DataTemplate>
</local:MultiChart.SeriesTemplate>
</local:MultiChart>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- End of not working charts -->
<!-- This chart works -->
<local:MultiChart
Title="{Binding ChartData.Title}"
SeriesSource="{Binding ChartData.DataSeriesList}">
<local:MultiChart.SeriesTemplate>
<DataTemplate>
<chartingToolkit:ColumnSeries
Title="Series Title"
ItemsSource="{Binding}"
IndependentValueBinding="{Binding Key}"
DependentValueBinding="{Binding Value}" />
</DataTemplate>
</local:MultiChart.SeriesTemplate>
</local:MultiChart>
<!-- End of working chart -->
</UniformGrid>
MultiChart.cs
public class MultiChart : System.Windows.Controls.DataVisualization.Charting.Chart
{
#region SeriesSource (DependencyProperty)
public IEnumerable SeriesSource
{
get
{
return (IEnumerable)GetValue(SeriesSourceProperty);
}
set
{
SetValue(SeriesSourceProperty, value);
}
}
public static readonly DependencyProperty SeriesSourceProperty = DependencyProperty.Register(
name: "SeriesSource",
propertyType: typeof(IEnumerable),
ownerType: typeof(MultiChart),
typeMetadata: new PropertyMetadata(
defaultValue: default(IEnumerable),
propertyChangedCallback: new PropertyChangedCallback(OnSeriesSourceChanged)
)
);
private static void OnSeriesSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
IEnumerable oldValue = (IEnumerable)e.OldValue;
IEnumerable newValue = (IEnumerable)e.NewValue;
MultiChart source = (MultiChart)d;
source.OnSeriesSourceChanged(oldValue, newValue);
}
protected virtual void OnSeriesSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
this.Series.Clear();
if (newValue != null)
{
foreach (object item in newValue)
{
DataTemplate dataTemplate = null;
if (this.SeriesTemplate != null)
{
dataTemplate = this.SeriesTemplate;
}
// load data template content
if (dataTemplate != null)
{
Series series = dataTemplate.LoadContent() as Series;
if (series != null)
{
// set data context
series.DataContext = item;
this.Series.Add(series);
}
}
}
}
}
#endregion
#region SeriesTemplate (DependencyProperty)
public DataTemplate SeriesTemplate
{
get
{
return (DataTemplate)GetValue(SeriesTemplateProperty);
}
set
{
SetValue(SeriesTemplateProperty, value);
}
}
public static readonly DependencyProperty SeriesTemplateProperty = DependencyProperty.Register(
name: "SeriesTemplate",
propertyType: typeof(DataTemplate),
ownerType: typeof(MultiChart),
typeMetadata: new PropertyMetadata(default(DataTemplate))
);
#endregion
}