Edit this page

Set Custom Fill For PointMarks Depending On Condition

It is common scenario that you would like to customize the appearance of the PointMarks in a Line Series. However since Line Series are Self-Drawing Series changing a property affects all PointMarks. This help article will demonstrate how to set custom Fill for PointMarks in a single Line Serie where it is set according to their YValue - *Blue *SolidColorBrush for those that are negative and *Red *for the positive ones. Additionally the Series Items Labels are set with Color according to their corresponding PointMark.

  • Create a new class named Data, which implements the INotifyPropertyChanged interface. It will be used as an ItemsSource for the chart control. The class has three properties:

  • Date - will be displayed on the X axis.

  • YValue - will be displayed on the Y axis.

  • PointMarkFill - will be applied to the PointMark Style to set the Fill for the PointMark.

public class Data : INotifyPropertyChanged
{
    private DateTime _date;
    private SolidColorBrush _pointMarkFill;
    private int _yvalue;
    public Data(DateTime date, int yvalue)
    {
        this._date = date;
        this._yvalue = yvalue;
        this.UpdatePointMarkVisibility();
    }
    public event PropertyChangedEventHandler PropertyChanged;
    public DateTime Date
    {
        get
        {
            return _date;
        }
        set
        {
            if (this._date == value)
                return;
            this._date = value;
            this.OnPropertyChanged("Date");
        }
    }
    public int YValue
    {
        get
        {
            return _yvalue;
        }
        set
        {
            if (this._yvalue == value)
                return;
            this._yvalue = value;
            this.OnPropertyChanged("YValue");
        }
    }
    public SolidColorBrush PointMarkFill
    {
        get
        {
            return _pointMarkFill;
        }
        private set
        {
            if (object.Equals(this._pointMarkFill, value))
                return;
            this._pointMarkFill = value;
            this.OnPropertyChanged("PointMarkVisibility");
        }
    }
    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    private void UpdatePointMarkVisibility()
    {
        if (this.YValue > 0)
            this.PointMarkFill = new SolidColorBrush(Colors.Red);
        else
            this.PointMarkFill = new SolidColorBrush(Colors.Blue);
    }
}
Public Class Data
    Implements INotifyPropertyChanged
    Private _date As Date
    Private _pointMarkFill As SolidColorBrush
    Private _yvalue As Integer
    Public Sub New(ByVal [date] As Date, ByVal yvalue As Integer)
        Me._date = [date]
        Me._yvalue = yvalue
        Me.UpdatePointMarkVisibility()
    End Sub
    Public Property Date As Date
        Get
            Return _date
        End Get
        Set(ByVal value As Date)
            If Me._date = value Then
                Return
            End If
            Me._date = value
            Me.OnPropertyChanged("Date")
        End Set
    End Property
    Public Property YValue() As Integer
        Get
            Return _yvalue
        End Get
        Set(ByVal value As Integer)
            If Me._yvalue = value Then
                Return
            End If
            Me._yvalue = value
            Me.OnPropertyChanged("YValue")
        End Set
    End Property
    Public Property PointMarkFill() As SolidColorBrush
        Get
            Return _pointMarkFill
        End Get
        Private Set(ByVal value As SolidColorBrush)
            If Object.Equals(Me._pointMarkFill, value) Then
                Return
            End If
            Me._pointMarkFill = value
            Me.OnPropertyChanged("PointMarkVisibility")
        End Set
    End Property
    Protected Overridable Sub OnPropertyChanged(ByVal propertyName As String)
        If Me.PropertyChangedEvent IsNot Nothing Then
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
        End If
    End Sub
    Private Sub UpdatePointMarkVisibility()
        If Me.YValue > 0 Then
            Me.PointMarkFill = New SolidColorBrush(Colors.Red)
        Else
            Me.PointMarkFill = New SolidColorBrush(Colors.Blue)
        End If
    End Sub

    Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
End Class

Note that the check for setting the PointMarkFill's value is added in the end of the code snippet above.Add the RadChart declaration:

<telerik:RadChart Name="chart"/>

Retemplate the default PointMark Style - Add Fill *Property databound to *DataItem.PointMarkFill property of the class. Add the Style between the starting and ending tags of the UserControl:

<Style x:Key="MyPointMark_Style" TargetType="telerik:PointMark">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="telerik:PointMark">
                <Canvas>
                    <Path x:Name="PART_PointMarkPath"
                    Canvas.Left="{TemplateBinding PointMarkCanvasLeft}"
                    Canvas.Top="{TemplateBinding PointMarkCanvasTop}"
                    Style="{TemplateBinding ShapeStyle}"
                    Width="{TemplateBinding Size}"
                    Height="{TemplateBinding Size}"
                    Fill="{Binding DataItem.PointMarkFill}"
                    Stroke="{Binding DataItem.PointMarkFill}"
                    Stretch="Fill">
                        <Path.Data>
                            <PathGeometry x:Name="PART_PointMarkPathGeometry" />
                        </Path.Data>
                    </Path>
                </Canvas>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Retemplate the default *SeriesItemLabel *Style so that the appropriate color will be set for each Label too:

<Style x:Key="MySeriesItemLabel_Style" TargetType="telerik:SeriesItemLabel">
    <Setter Property="Padding" Value="2,0" />
    <Setter Property="IsHitTestVisible" Value="False"/>
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content }" TextAlignment="Center" />
            </DataTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="Template" >
        <Setter.Value>
            <ControlTemplate TargetType="telerik:SeriesItemLabel">
                <Canvas x:Name="PART_MainContainer">
                    <Path                            
                Visibility="{TemplateBinding ConnectorVisibility}"
                Style="{TemplateBinding ConnectorStyle}"
                Stroke="{TemplateBinding Stroke}" 
                StrokeThickness="{TemplateBinding StrokeThickness}">
                        <Path.Data>
                            <PathGeometry >
                                <PathGeometry.Figures>
                                    <PathFigure x:Name="PART_Connector">
                                        <PathFigure.Segments>
                                            <PolyLineSegment />
                                        </PathFigure.Segments>
                                    </PathFigure>
                                </PathGeometry.Figures>
                            </PathGeometry>
                        </Path.Data>
                    </Path>
                    <Border x:Name="PART_TextContainer"
                Style="{TemplateBinding LabelStyle}"
                BorderBrush="{TemplateBinding Stroke}"
                Background="{Binding DataItem.PointMarkFill}"
                Width="{TemplateBinding Width}"
                Height="{TemplateBinding Height}">
                        <ContentPresenter Margin="{TemplateBinding Padding}" />
                    </Border>
                </Canvas>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

The chart is populated with data in code-behind using Manual Series Mappings. The last line in the code snippet demonstrates how the Style for the PointMarks can be set.

List<Data> exportData = new List<Data>();
DateTime baseDate = DateTime.Today;
Random r = new Random();
for (int i = 0; i < 30; i++)
{
    exportData.Add(new Data(baseDate.AddDays(i), r.Next(-20, 20)));
}
SeriesMapping mapping = new SeriesMapping();
mapping.ItemMappings.Add(new ItemMapping("YValue", DataPointMember.YValue));
mapping.ItemMappings.Add(new ItemMapping("Date", DataPointMember.XCategory));
chart.ItemsSource = exportData;
chart.SeriesMappings.Add(mapping);
chart.DefaultView.ChartArea.AxisX.IsDateTime = true;
chart.DefaultView.ChartArea.AxisX.LabelRotationAngle = 45;
chart.DefaultView.ChartArea.AxisX.DefaultLabelFormat = "dd-MM-yy";
LineSeriesDefinition line = new LineSeriesDefinition();
chart.DefaultSeriesDefinition = line;
line.ShowPointMarks = true;
line.ShowItemLabels = true;
chart.DefaultSeriesDefinition.PointMarkItemStyle = this.Resources["MyPointMark_Style"] as Style;
chart.DefaultSeriesDefinition.SeriesItemLabelStyle = this.Resources["MySeriesItemLabel_Style"] as Style;
Dim exportData As New List(Of Data)()
Dim baseDate As Date = Date.Today
Dim r As New Random()
For i As Integer = 0 To 29
    exportData.Add(New Data(baseDate.AddDays(i), r.Next(-20, 20)))
Next i
Dim mapping As New SeriesMapping()
mapping.ItemMappings.Add(New ItemMapping("YValue", DataPointMember.YValue))
mapping.ItemMappings.Add(New ItemMapping("Date", DataPointMember.XCategory))
chart.ItemsSource = exportData
chart.SeriesMappings.Add(mapping)
chart.DefaultView.ChartArea.AxisX.IsDateTime = True
chart.DefaultView.ChartArea.AxisX.LabelRotationAngle = 45
chart.DefaultView.ChartArea.AxisX.DefaultLabelFormat = "dd-MM-yy"
Dim line As New LineSeriesDefinition()
chart.DefaultSeriesDefinition = line
line.ShowPointMarks = True
line.ShowItemLabels = True
chart.DefaultSeriesDefinition.PointMarkItemStyle = TryCast(Me.Resources("MyPointMark_Style"), Style)
chart.DefaultSeriesDefinition.SeriesItemLabelStyle = TryCast(Me.Resources("MySeriesItemLabel_Style"), Style)

The result can be seen on the image below: