2013-10-11 65 views
1

我正在執行一個執行儀表板,它應該能夠擁有任意數量的圖表,並且每個系列都有多個圖表。我正在使用WPF工具包。如何使用WPF Toolkit綁定多個圖表與多個系列?

我遇到的第一個問題是將多個系列綁定到一個圖表。我找到了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 
} 

回答

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) 
    ) 
); 
相關問題