New to Telerik UI for WPF? Download free 30-day trial

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: WPF RadChart

In this article