We have a requirement where we need to change the color of column series based on the underlying value. We have a reference value set to 0 for NumericYAxis which means negative value bars need to displayed with different color. Also some bars need to be painted differently based on estimate val etc.
It would be great if we can override some sort of DataTemplate to drive this req based on the data-triggers
please see:
http://community.infragistics.com/forums/p/48210/256989.aspx#256989
-Graham
I was wondering since our requirement is pretty refined, display different color of bar for negative values (our ref point is 0)
We tried using a following style trigger on ColumnSeries, binding seems to be working but trigger is not working.
<Style x:Key="ColumnStyle" TargetType="{x:Type Charts:ColumnSeries}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsNeg}" Value="true">
<Setter Property="Brush" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsNeg}" Value="false">
<Setter Property="Brush" Value="Blue"/>
</Style.Triggers>
</Style>
Any pointers??
Its not simple as we don't let you specify a data template for the columns. I would recommend making a feature request.
But here is how you could do it:
The xaml:
<Window.Resources> <local:TestData x:Key="data" /> </Window.Resources> <Grid> <igChart:XamDataChart x:Name="theChart"> <igChart:XamDataChart.Resources> <Style TargetType="Rectangle"> <Setter Property="local:StyleBinder.StyleBinderHelper"> <Setter.Value> <local:StyleBinderHelper> <local:StyleBinderHelper.Template> <DataTemplate> <local:RectangleColorChanger YAxis="{Binding OuterContext.Series.YAxis}" Value="{Binding Owner.ActualHeight}" Threshold="0" Rectangle="{Binding Owner}" /> </DataTemplate> </local:StyleBinderHelper.Template> </local:StyleBinderHelper> </Setter.Value> </Setter> </Style> </igChart:XamDataChart.Resources> <igChart:XamDataChart.Axes> <igChart:NumericYAxis x:Name="yAxis" /> <igChart:CategoryXAxis x:Name="xAxis" ItemsSource="{StaticResource data}" Label="{}{Label}"/> </igChart:XamDataChart.Axes> <igChart:XamDataChart.Series> <igChart:ColumnSeries x:Name="series" ItemsSource="{StaticResource data}" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}" ValueMemberPath="Value" /> </igChart:XamDataChart.Series> </igChart:XamDataChart> </Grid>
And the code behind:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } public class TestData : ObservableCollection<TestDataItem> { public TestData() { Add(new TestDataItem() { Label = "A", Value = 1 }); Add(new TestDataItem() { Label = "B", Value = 2 }); Add(new TestDataItem() { Label = "C", Value = 3 }); Add(new TestDataItem() { Label = "D", Value = -1 }); Add(new TestDataItem() { Label = "E", Value = -2 }); Add(new TestDataItem() { Label = "F", Value = -1 }); Add(new TestDataItem() { Label = "G", Value = 1 }); Add(new TestDataItem() { Label = "H", Value = 2 }); } } public class TestDataItem { public string Label { get; set; } public double Value { get; set; } } 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 ThresholdProperty = DependencyProperty.Register( "Threshold", typeof(double), typeof(RectangleColorChanger), new PropertyMetadata(0.0, (o, e) => (o as RectangleColorChanger) .ThresholdChanged(e))); private void ThresholdChanged( DependencyPropertyChangedEventArgs e) { UpdateColor(); } public double Threshold { get { return (double)GetValue(ThresholdProperty); } set { SetValue(ThresholdProperty, value); } } 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 (YAxis == null) { return; } if (Rectangle == null) { return; } Rect viewport = new Rect(0,0,YAxis.ActualWidth, YAxis.ActualHeight); double zero = YAxis.GetScaledValue(YAxis.ReferenceValue, YAxis.Chart.WindowRect, viewport); double top = Rectangle.TransformToVisual(YAxis).Transform(new Point(0, 0)).Y; double bottom = Rectangle.TransformToVisual(YAxis).Transform(new Point(0, Rectangle.Height)).Y; double val = 0; if (top < zero && bottom <= zero) { val = YAxis.GetUnscaledValue(top, YAxis.Chart.WindowRect, viewport); } else { val = YAxis.GetUnscaledValue(bottom, YAxis.Chart.WindowRect, viewport); } if (val < Threshold) { Rectangle.Fill = new SolidColorBrush(Colors.Red); } } private void RectangleChanged(DependencyPropertyChangedEventArgs e) { UpdateColor(); } public Rectangle Rectangle { get { return (Rectangle)GetValue(RectangleProperty); } set { SetValue(RectangleProperty, value); } } private void ValueChanged(DependencyPropertyChangedEventArgs e) { UpdateColor(); } public static readonly DependencyProperty YAxisProperty = DependencyProperty.Register( "YAxis", typeof(NumericYAxis), typeof(RectangleColorChanger), new PropertyMetadata(null, (o, e) => (o as RectangleColorChanger) .YAxisChanged(e))); private void YAxisChanged( DependencyPropertyChangedEventArgs e) { UpdateColor(); } public NumericYAxis YAxis { get { return (NumericYAxis)GetValue(YAxisProperty); } set { SetValue(YAxisProperty, value); } } }
Hope this helps!
This solution has worked fantastic for us. Unfortunately, we just upgraded to version 13.2 and it no longer works. Any idea on why it broke with the upgrade?
Thanks for all of the help.
Any updates on this. I believe it has something to do with changes to the way the chart is drawn in version 13.1. We are also experiencing issues with the tool tip display. It looks like the coordinates are off. If you hover over a bar you get the tool tip for the point before instead of the point you are actually on. My guess is this is actually a similar issue. If the chart size changes at all, it is not reflected the same way it was in version 12. If no answer/solution is produced soon, we will be rolling back to version 12.