首页 文章

如何使用WPF Toolkit将多个图表绑定到多个系列?

提问于
浏览
1

我正在制作一个执行仪表板,它应该能够包含任意数量的图表,每个图表都包含任意数量的系列 . 我正在使用WPF工具包 .

我遇到的第一个问题是将多个系列绑定到图表 . 我找到了Beat Kiener's excellent blogpost on binding multiple series to a chart,它工作得很好,直到我把它放在一个物品控制器中,我必须这样做以满足我的"any number of charts"要求 .

在我看来,下面的代码应该工作,但事实并非如此 . 任何人都可以解释为什么下面的代码不起作用,或提供另一种方法来使用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
}

1 回答

  • 1

    我终于弄明白了 .

    MultiChart 放在 ItemsControl 内时, SeriesSource 属性设置在 SeriesTemplate 属性之前 . 这不起作用,因为 OnSeriesSourceChanged 方法需要知道 SeriesTemplate 是什么 . 我的解决方法是只要在 SeriesTemplate 更改时调用 OnSeriesSourceChanged 方法 .

    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)
        )
    );
    

相关问题