我正在制作一个执行仪表板,它应该能够包含任意数量的图表,每个图表都包含任意数量的系列。我正在使用WPF工具包。
我遇到的第一个问题是将多个系列绑定到图表。我发现Beat Kiener's excellent blogpost on binding multiple series to a chart效果很好,直到我把它放在物品控件中,我必须这样做以满足我的“任意数量的图表”要求。
在我看来,下面的代码应该可行,但事实并非如此。任何人都可以解释为什么下面的代码不起作用,或提供另一种方法来使用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
}
答案 0 :(得分:1)
我终于明白了。
当您将MultiChart
放在ItemsControl
内时,SeriesSource
属性设置在SeriesTemplate
属性之前。这不起作用,因为OnSeriesSourceChanged
方法需要知道SeriesTemplate
是什么。我的解决方法是只要在OnSeriesSourceChanged
发生更改时调用SeriesTemplate
方法。
private static void OnSeriesTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataTemplate oldValue = (DataTemplate)e.OldValue;
DataTemplate newValue = (DataTemplate)e.NewValue;
MultiChart source = (MultiChart)d;
source.OnSeriesTemplateChanged(oldValue, newValue);
}
protected virtual void OnSeriesTemplateChanged(DataTemplate oldValue, DataTemplate newValue)
{
this.SeriesTemplate = newValue;
OnSeriesSourceChanged(SeriesSource, SeriesSource);
}
public static readonly DependencyProperty SeriesTemplateProperty = DependencyProperty.Register(
name: "SeriesTemplate",
propertyType: typeof(DataTemplate),
ownerType: typeof(MultiChart),
typeMetadata: new PropertyMetadata(
defaultValue: default(DataTemplate),
propertyChangedCallback: new PropertyChangedCallback(OnSeriesTemplateChanged)
)
);