I have been struggling to find out how to format the columns (or bars) in a XamDataChart ColumnSeries based it's value. I understand that I could do this by multiple series's but this does not work correctly in my case. I am looking for something similar to this example (http://forums.infragistics.com/silverlight/codesamples/custom-chart-data-point-templates.aspx) but using the style of the column, not a marker.
The data chart currently does not allow for changing the template of the columns in a column series. You could make a feature request to this effect.
In what way is the automatic coloring of the series not working to your expectations?
You can use an implicit style to modify the style of the rectangles used by a series, but you would have to do some tricky things there, depending on what your goal is. Could you elaborate on what you are trying to achieve?
-Graham
Here's an example of how you can do interesting things with an implicit style for the rectangles of the series:
The xaml:
<UserControl.Resources> <local:TestData x:Key="data" /> <local:TestData x:Key="data2" /> <Style TargetType="Rectangle"> <Style.Setters> <Setter Property="local:StyleBinder.StyleBinderHelper"> <Setter.Value> <local:StyleBinderHelper> <local:StyleBinderHelper.Template> <DataTemplate> <local:RectangleColorChanger Value="{Binding Owner.Height}" MaxValue="{Binding OuterContext.Series.ActualHeight}" Rectangle="{Binding Owner}" /> </DataTemplate> </local:StyleBinderHelper.Template> </local:StyleBinderHelper> </Setter.Value> </Setter> </Style.Setters> </Style> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <igChart:XamDataChart x:Name="theChart" Legend="{Binding ElementName=legend}"> <igChart:XamDataChart.Axes> <igChart:CategoryXAxis x:Name="xAxis" ItemsSource="{StaticResource data}" Label="{}{Label}" /> <igChart:NumericYAxis x:Name="yAxis" /> </igChart:XamDataChart.Axes> <igChart:XamDataChart.Series> <igChart:ColumnSeries x:Name="theLine" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}" ItemsSource="{StaticResource data}" ValueMemberPath="Value" /> <igChart:ColumnSeries x:Name="theLine2" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}" ItemsSource="{StaticResource data2}" ValueMemberPath="Value" /> </igChart:XamDataChart.Series> </igChart:XamDataChart> </Grid>
And the code behind:
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } } public class TestDataItem { public string Label { get; set; } public double Value { get; set; } } public class TestData : ObservableCollection<TestDataItem> { private static Random _rand = new Random(); public TestData() { for (int i = 0; i < 10; i++) { Add(new TestDataItem() { Label = i.ToString(), Value = _rand.NextDouble() * 10.0 }); } } } public static class StyleBinder { public static readonly DependencyProperty StyleBinderHelperProperty = DependencyProperty.RegisterAttached( "StyleBinderHelper", typeof(StyleBinderHelper), typeof(StyleBinder), new PropertyMetadata(null, (o, e) => StyleBinderHelperChanged(o, e))); private static void StyleBinderHelperChanged( DependencyObject o, DependencyPropertyChangedEventArgs e) { FrameworkElement ele = o as FrameworkElement; if (ele == null) { return; } BindingExpression be = ele.GetBindingExpression ( StyleBinder.StyleBinderContextProperty); if (be == null) { ele.SetBinding(StyleBinderContextProperty, new Binding()); } if (e.NewValue != null) { ((StyleBinderHelper)e.NewValue).PushContent(ele); } } public static void SetStyleBinderHelper( DependencyObject target, StyleBinderHelper value) { target.SetValue(StyleBinderHelperProperty, value); } public static StyleBinderHelper GetStyleBinderHelper( DependencyObject target) { return (StyleBinderHelper)target.GetValue(StyleBinderHelperProperty); } public static readonly DependencyProperty StyleBinderContentProperty = DependencyProperty.RegisterAttached( "StyleBinderContent", typeof(FrameworkElement), typeof(StyleBinder), new PropertyMetadata(null, (o, e) => StyleBinderContentChanged(o, e))); private static void StyleBinderContentChanged( DependencyObject o, DependencyPropertyChangedEventArgs e) { } public static void SetStyleBinderContent( DependencyObject target, FrameworkElement value) { target.SetValue(StyleBinderContentProperty, value); } public static FrameworkElement GetStyleBinderContent( DependencyObject target) { return (FrameworkElement)target.GetValue(StyleBinderContentProperty); } public static readonly DependencyProperty StyleBinderContextProperty = DependencyProperty.RegisterAttached( "StyleBinderContext", typeof(object), typeof(StyleBinder), new PropertyMetadata(null, (o, e) => StyleBinderContextChanged(o, e))); private static void StyleBinderContextChanged( DependencyObject o, DependencyPropertyChangedEventArgs e) { FrameworkElement content = StyleBinder.GetStyleBinderContent(o); if (content != null) { content.DataContext = new HelperContext() { OuterContext = e.NewValue, Owner = o as FrameworkElement }; } } public static void SetStyleBinderContext( DependencyObject target, object value) { target.SetValue(StyleBinderContextProperty, value); } public static object GetStyleBinderContext( DependencyObject target) { return target.GetValue(StyleBinderContextProperty); } } public class StyleBinderHelper : FrameworkElement { internal void PushContent(FrameworkElement ele) { if (Template == null) { return; } FrameworkElement content = Template.LoadContent() as FrameworkElement; if (content == null) { return; } content.DataContext = new HelperContext() { OuterContext = StyleBinder.GetStyleBinderContext(ele), Owner = ele }; StyleBinder.SetStyleBinderContent(ele, content); } public DataTemplate Template { get; set; } } public class HelperContext : INotifyPropertyChanged { private object _outerContext; public object OuterContext { get { return _outerContext; } set { _outerContext = value; RaisePropertyChanged("OuterContext"); } } private FrameworkElement _owner; public FrameworkElement Owner { get { return _owner; } set { _owner = value; RaisePropertyChanged("Owner"); } } public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } public class RectangleColorChanger : FrameworkElement { public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( "Value", typeof(double), typeof(RectangleColorChanger), new PropertyMetadata(0.0, (o, e) => (o as RectangleColorChanger) .ValueChanged(e))); public double Value { get { return (double)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } public static readonly DependencyProperty MaxValueProperty = DependencyProperty.Register( "MaxValue", typeof(double), typeof(RectangleColorChanger), new PropertyMetadata(0.0, (o, e) => (o as RectangleColorChanger) .MaxValueChanged(e))); private void MaxValueChanged( DependencyPropertyChangedEventArgs e) { UpdateColor(); } public double MaxValue { get { return (double)GetValue(MaxValueProperty); } set { SetValue(MaxValueProperty, MaxValue); } } public static readonly DependencyProperty RectangleProperty = DependencyProperty.Register( "Rectangle", typeof(Rectangle), typeof(RectangleColorChanger), new PropertyMetadata(null, (o, e) => (o as RectangleColorChanger) .RectangleChanged(e))); private void UpdateColor() { if (Rectangle == null) { return; } Rectangle.Fill = new SolidColorBrush( new Color() { A = 255, B = 0, G = 0, R = (byte)(((double)Value / MaxValue) * 255.0) }); } private void RectangleChanged(DependencyPropertyChangedEventArgs e) { UpdateColor(); } public Rectangle Rectangle { get { return (Rectangle)GetValue(RectangleProperty); } set { SetValue(RectangleProperty, value); } } private void ValueChanged(DependencyPropertyChangedEventArgs e) { UpdateColor(); } }
This is just an example, of course, if you can fill in more details we can help identify the best course to take. Here's a screenshot of what the above produces:
it basically just adjusts the color based on the height of the rectangle.
Hope this helps!
Most of the above mechanism is only necessary because Silverlight doesn't yet allow bindings to be applied in styles.
Is this still not possible in the latest XamDataChart?
Hello,
Currently the approach Graham suggested seems to be the best one for the moment, to achieve the functionality you want.
Hope it helps you.
Hi,
I was just checking for the same functionality. This implementation is somewhat similar to my requirement.
Just the difference is that this implementation is based on the value of the bar/column, and I want to have totally different color in each bar/series. Each series will only contain 1 DataItem only.
I'm able to do the same implementation, with single series and multiple dataitems on single color. But I want the same implementation with different colors, whether single series with multiple dataitems or multiple series with single dataitem/series.
How can I achieve this?