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!
Thanks Graham, you have always been a immense help.
This solution would work for this case i.e. display bar in different color for negative values. I forgot to mention that we have another scenario where we want to display last column as grey. I saw you defined dependency prop as Threshold to differentiate between +ive and neg values, wondering if there is a way to figure out the last col of the column series.