How to reset the WPF Toolkit Chart colour palette when resetting the data

…衆ロ難τιáo~ 提交于 2019-12-05 18:31:05
ToMa

I've got the same problem, and I found another solution. Maybe it's not the better one, but it works.

I added an int property to my object binding on the PieSeries, who represent the element's index in the ObservableCollection. Then I created a ResourceDictionaryCollection which contains all the default colors of the Palette:

<datavis:ResourceDictionaryCollection x:Key="CouleursGraphique">
    <!-- Blue -->
    <ResourceDictionary>
      <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
        <GradientStop Color="#FFB9D6F7" />
        <GradientStop Color="#FF284B70" Offset="1" />
      </RadialGradientBrush>
    </ResourceDictionary>
    <!-- Red -->
    <ResourceDictionary>
      <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
        <GradientStop Color="#FFFBB7B5" />
        <GradientStop Color="#FF702828" Offset="1" />
      </RadialGradientBrush>
    </ResourceDictionary>
    <!-- Light Green -->
    <ResourceDictionary>
      <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
        <GradientStop Color="#FFB8C0AC" />
        <GradientStop Color="#FF5F7143" Offset="1" />
      </RadialGradientBrush>
    </ResourceDictionary>
    <!-- Yellow -->
    <ResourceDictionary>
      <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
        <GradientStop Color="#FFFDE79C" />
        <GradientStop Color="#FFF6BC0C" Offset="1" />
      </RadialGradientBrush>
    </ResourceDictionary>
    <!-- Indigo -->
    <ResourceDictionary>
      <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
        <GradientStop Color="#FFA9A3BD" />
        <GradientStop Color="#FF382C6C" Offset="1" />
      </RadialGradientBrush>
    </ResourceDictionary>
    <!-- Magenta -->
    <ResourceDictionary>
      <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
        <GradientStop Color="#FFB1A1B1" />
        <GradientStop Color="#FF50224F" Offset="1" />
      </RadialGradientBrush>
    </ResourceDictionary>
    <!-- Dark Green -->
    <ResourceDictionary>
      <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
        <GradientStop Color="#FF9DC2B3" />
        <GradientStop Color="#FF1D7554" Offset="1" />
      </RadialGradientBrush>
    </ResourceDictionary>
    <!-- Gray Shade -->
    <ResourceDictionary>
      <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
        <GradientStop Color="#FFB5B5B5" />
        <GradientStop Color="#FF4C4C4C" Offset="1" />
      </RadialGradientBrush>
    </ResourceDictionary>
    <!-- Blue -->
    <ResourceDictionary>
      <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
        <GradientStop Color="#FF98C1DC" />
        <GradientStop Color="#FF0271AE" Offset="1" />
      </RadialGradientBrush>
    </ResourceDictionary>
    <!-- Brown -->
    <ResourceDictionary>
      <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
        <GradientStop Color="#FFC1C0AE" />
        <GradientStop Color="#FF706E41" Offset="1" />
      </RadialGradientBrush>
    </ResourceDictionary>
    <!-- Cyan -->
    <ResourceDictionary>
      <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
        <GradientStop Color="#FFADBDC0" />
        <GradientStop Color="#FF446A73" Offset="1" />
      </RadialGradientBrush>
    </ResourceDictionary>
    <!-- Special Blue -->
    <ResourceDictionary>
      <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
        <GradientStop Color="#FF2F8CE2" />
        <GradientStop Color="#FF0C3E69" Offset="1" />
      </RadialGradientBrush>
    </ResourceDictionary>
    <!-- Gray Shade 2 -->
    <ResourceDictionary>
      <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
        <GradientStop Color="#FFDCDCDC" />
        <GradientStop Color="#FF757575" Offset="1" />
      </RadialGradientBrush>
    </ResourceDictionary>
    <!-- Gray Shade 3 -->
    <ResourceDictionary>
      <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
        <GradientStop Color="#FFF4F4F4" />
        <GradientStop Color="#FFB7B7B7" Offset="1" />
      </RadialGradientBrush>
    </ResourceDictionary>
    <!-- Gray Shade 4 -->
    <ResourceDictionary>
      <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
        <GradientStop Color="#FFF4F4F4" />
        <GradientStop Color="#FFA3A3A3" Offset="1" />
      </RadialGradientBrush>
    </ResourceDictionary>
  </datavis:ResourceDictionaryCollection>

I added a converter that returns the color at the specified index of ResourceDictionaryCollection.

 /// <summary>
    /// Convertit une valeur.
    /// </summary>
    /// <param name="value">Valeur produite par la source de liaison.</param>
    /// <param name="targetType">Type de la propriété de cible de liaison.</param>
    /// <param name="parameter">Paramètre de convertisseur à utiliser.</param>
    /// <param name="culture">Culture à utiliser dans le convertisseur.</param>
    /// <returns>
    /// Une valeur convertie. Si la méthode retourne null, la valeur Null valide est utilisée.
    /// </returns>
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ResourceDictionaryCollection listeCouleurs = parameter as ResourceDictionaryCollection;
        int indice = (int)value;

        return listeCouleurs[indice % listeCouleurs.Count]["Background"];
    }

And i used all this elements in the Xaml like this:

  <charting:Chart.Series>
<charting:PieSeries ItemsSource="{Binding Path=Donnees}"
                    DependentValuePath="Valeur"
                    IndependentValuePath="Libelle">
  <charting:PieSeries.Palette>
    <datavis:ResourceDictionaryCollection>
      <ResourceDictionary>
        <Style x:Key="DataPointStyle" TargetType="Control">
          <Setter Property="Background" Value="{Binding Path=Index, Converter={StaticResource convCouleur}, ConverterParameter={StaticResource CouleursGraphique}}"/>
        </Style>
      </ResourceDictionary>
    </datavis:ResourceDictionaryCollection>
  </charting:PieSeries.Palette>
</charting:PieSeries>

I hope that answer can help you.

If you don't want to add another property to your data and a converter, you can use reflection.

To aid in easy data presentation, wpftoolkit data series have an inheritable ResourceDictionaryDispenser in charge with providing a different set of resource dictionaries every time it's called. The ResourceDictionaryDispenser in each DataPointSeries gets its own enumerators from the one in the Chart object.

Too bad the ResourceDictionaryDispenser property in Chart is private, as is its Reset() method. You can use the following code, though:

Type t = typeof(Chart);

PropertyInfo fResDispenser = t.GetProperty("ResourceDictionaryDispenser",
    BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty);

resDispenser = fResDispenser.GetValue(chart, null);

ResDispenserReset = resDispenser.GetType().GetMethod("Reset",
    BindingFlags.NonPublic | BindingFlags.Instance);

ResDispenserReset.Invoke(resDispenser, null);

Once you stored a reference to the method and the resource dispenser, you should avoid direct binding your data source with the series' ItemsSource. Intercept instead your data update (maybe with the INotifyPropertyChanged.PropertyChanged event) and act like this:

pieDataSeries.ItemsSource = null;
ResDispenserReset.Invoke(resDispenser, null);
pieDataSeries.ItemsSource = [new data set];

tested and 100% working.

The XAML is like this:

<UserControl x:Class="Datamanager.Widgets.SubunitsPieChart"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:gra="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit">
    <gra:Chart Margin="5"
               x:Name="chart"
               HorizontalAlignment="Stretch"
               VerticalAlignment="Stretch"
               BorderThickness="0">
        <gra:PieSeries x:Name="chartSeries"
                       DependentValuePath="Value"
                       IndependentValuePath="Key" />
    </gra:Chart>
</UserControl>

you should add these usings too.

using System.Reflection;
using System.Windows.Controls.DataVisualization;
using System.Windows.Controls.DataVisualization.Charting;
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!