4
votes

I have a huge problem that I can't figure out. Let's say that I have five different fruits, and I want each of them to be associated with a certain color. Let's say that I have three "baskets" which contain zero or more of said fruits.

When I Make Pie charts for my three baskets, Each wedge is just some random color that is presumable picked by the control. How would I say, make the blueberries blue, bannanas yellow, etc. in the chart?

I know this is a weird question, but I can't think of a simpler way to describe it.

I don't care if the solution is in XAML or code, just as long as it works.

3

3 Answers

5
votes

I have found the solution, after much swearing and investigation. There are a lot of moving parts here, so I am going to keep each as brief as possible while still conveying the main points.

For starters I have a collection of objects that I am trying to keep track of:

public class PileOfFruit
{
  public string Name {get; set; }
  public int Count { get; set; }
}

In my view model, I have a collection of those objects.

public class BasketVM
{
...
    private ObservableCollection<PileOfFruit> _FruitBasket = new ObservableCollection<PileOfFruit>();
    public ObservableCollection<PileOfFruit> FruitBasket
    {
      get { return _FruitBasket; }
    }
...
}

In my view I will define the pie chart that will display the quantites of the fruits in the basket. The most important factor here is the template binding to SliceTemplate

<chartingToolkit:Chart x:Name="ExampleChart">
    <chartingToolkit:PieSeries ItemsSource={Binding FruitBasket
                               DependentValueBinding="{Binding Count}" 
                               IndependentValueBinding="{Binding Name}">
        <chartingToolkit:PieSeries.Palette>
            <visualizationToolkit:ResourceDictionaryCollection>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="Control">
                    <Setter Property="Template" Value="{StaticResource SliceTemplate}"/>
                </Style>

Now in app.xaml or some other place we can drop in the template for the PieDataSeries object. Pay close attention to the value on Fill It is bound to the independent value which will be something like 'banana' 'grape' or whatever. This in turn is passed off to a value converter.

<converters:FruitToColorConverter x:Key="FruitToColorConverter"/>

<ControlTemplate x:Key="SliceTemplate" TargetType="chart:PieDataPoint">
  <Path Data="{TemplateBinding Geometry}"
        Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IndependentValue, Converter={StaticResource FruitToColorConverter}}"
        Stroke="{TemplateBinding BorderBrush}">
    ....

The associated data converter is what will finally set the color that we want. So if we do something like this...

public class FruitToColorConverter : IValueConverter
{
  private SolidColorBrush Default = new SolidColorBrush(Colors.Black);

  public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
    if (value == null || (!(value is string))) { return Default; }

    switch (value as string)
    {
      case "Apple":
        return new SolidColorBrush(Colors.Red);
      case "BlueBerry":
        return new SolidColorBrush(Colors.Blue);
      default:
        return Default;
        ......

And that is how you get the correct colors each and every time. If I left anything out or should clarify, please let me know so I can make corrections. There are a lot of moving parts here.. =P

3
votes

You can define your own color palette for the chart, but it will automatically pick the colors for the dataitems as they are appears in the palette. So no (easy?) way to tell the chart to display blueberries blue, bannanas yellow, etc. What you can do is to tell the chart to display the first item blue, second item yellow etc, and put bluberries first, bannanas second etc. in the datasource.

Some sample to define your own paletta:

<chartingToolkit:Chart x:Name="ExampleChart">
    <chartingToolkit:PieSeries>
        <chartingToolkit:PieSeries.ItemsSource >
            <toolkit:ObjectCollection>
                <sys:Double>1</sys:Double>
                <sys:Double>2.3</sys:Double>
                <sys:Double>3.5</sys:Double>
                <sys:Double>5</sys:Double>
            </toolkit:ObjectCollection>
        </chartingToolkit:PieSeries.ItemsSource >
        <chartingToolkit:PieSeries.Palette>
            <visualizationToolkit:ResourceDictionaryCollection>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="Control">
                    <Setter Property="Background" Value="Red"/>
                </Style>
            </ResourceDictionary>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="Control">
                    <Setter Property="Background" Value="Green"/>
                </Style>
            </ResourceDictionary>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="Control">
                    <Setter Property="Background" Value="Blue"/>
                </Style>
            </ResourceDictionary>
            </visualizationToolkit:ResourceDictionaryCollection>
        </chartingToolkit:PieSeries.Palette>
    </chartingToolkit:PieSeries >
</chartingToolkit:Chart >

EDIT: The interesting namespeces:

xmlns:visualizationToolkit="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit" 
xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
-1
votes

Here is what I've found: The colors aren't really random: There is a sequense of pallettes which repeats every 5ish times (the number actually doesn't matter). My workaround is simpler: every time I have new data to be displayed I recreate the piechart. In this way the color pallette will always start from the same colors (meaning that it will never change). This means that you need to have a method that programatically rebuilds your PieChart (do not have it in XAML, just have there a placeholder and call the "PieChartBuilder" method ). I think this is less code (also less bugs :) ).