MindFusion.Wpf Pack Programmer's Guide
General Template

The RealTimeChart template consists of a grid container, which lays out the various chart parts/ The grid consists initially of 3 rows and 3 columns. In the middle (row 1, column 1), we have the plot area, which is a FrameworkElement. The PlotArea draws the chart together with the X-axis.

PlotArea Declaration (XAML)  Copy Code

<local:PlotArea
        x:Name="plotArea"
        ClipToBounds="False"
        Grid.Column="1" Grid.Row="1"
        XAxis="{TemplateBinding XAxis}"
        SeriesCollection="{TemplateBinding SeriesCollection}"
        ScrollOffset="{TemplateBinding ScrollOffset}"
        BitmapOffset="{TemplateBinding BitmapOffset}">
</local:PlotArea>

Y-axes and Y2-axes are rendered in an ItemsControl. There are two ItemsControl instances - one to the left and one to the right of the PlotArea element:

Y-axes Declaration (XAML)  Copy Code

<!-- left Y axes -->
<ItemsControl
       Grid.Row="1" Grid.Column="0"
       Style="{StaticResource YAxisControl}"
       ItemsSource="{TemplateBinding YAxisCollection}" />

<!-- right Y axes -->
<ItemsControl
       Grid.Row="1" Grid.Column="2"
       Style="{StaticResource YAxisControl}"
       ItemsSource="{TemplateBinding Y2AxisCollection}" />

The legend is an ItemsControl as well. It is bound to the SeriesCollection of the chart and is visible when ShowLegend is true. Initially it is placed at the bottom of the chart, in the middle (last grid row, middle grid column):

Legend Declaration (XAML)  Copy Code

<!-- legend template -->
       <local:Legend
        x:Name="legend"
        ItemsSource="{TemplateBinding SeriesCollection}"
        Grid.Row="2" Grid.Column="1"
        Background="{TemplateBinding LegendBackground}"
        BorderBrush="{TemplateBinding LegendBorderBrush}"               
        BorderThickness="1"
        Width="{TemplateBinding LegendWidth}"
        Height="{TemplateBinding LegendHeight}"
        Orientation="{TemplateBinding LegendOrientation}"
        HorizontalAlignment="{TemplateBinding LegendHorizontalAlignment}"
        VerticalAlignment="{TemplateBinding LegendVerticalAlignment}"
        Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ShowLegend, Converter={StaticResource chartToLegendVisibilityConverter}}">
</local:Legend>

The title is a TextBlock located at the top:

Title Declaration (XAML)  Copy Code

<TextBlock
        x:Name="title"
        Grid.Row="0" Grid.Column="1"
        Text="{TemplateBinding TitleText}"
        HorizontalAlignment="{TemplateBinding TitleHorizontalAlignment}"
        VerticalAlignment="{TemplateBinding TitleVerticalAlignment}"
        FontFamily="{TemplateBinding TitleFontFamily}"
        FontSize="{TemplateBinding TitleFontSize}" />

The Y-axis template

The Y and Y2 axes are rendered by custom ItemsControl, which uses custom AxisRenderer (derived from FrameworkElement). The axes are arranged in a horizontal StackPanel.

The Y-axis Control Template (XAML)  Copy Code

<Style x:Key="YAxisControl" TargetType="{x:Type ItemsControl}" xmlns:x="http://mindfusion.eu">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type ItemsControl}">
        <ItemsPresenter />
      </ControlTemplate>
    </Setter.Value>
  </Setter>
  <Setter Property="ItemsPanel">
    <Setter.Value>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal"></StackPanel>
      </ItemsPanelTemplate>
    </Setter.Value>
  </Setter>
  <Setter Property="ItemTemplate">
    <Setter.Value>
      <DataTemplate DataType="{x:Type local:Axis}">
        <local:AxisRenderer XAxis="{Binding Path=XAxis, ElementName=plotArea}" YAxis="{Binding}" xmlns:local="http://mindfusion.eu"></local:AxisRenderer>
      </DataTemplate>
    </Setter.Value>
  </Setter>
</Style>

The Legend template

Each item is a StackPanel, which contains a Path Shape and a string. The StackPanel-s are arranged in a WrapPanel. The SeriesToGeometryConverter converts the ScatterType of each Series to a Path.Data object.

The Legend Control Template (XAML)  Copy Code
<Style TargetType="{x:Type local:Legend}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type local:Legend}">
        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{TemplateBinding CornerRadius}" Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}" Margin="{TemplateBinding Margin}">
          <ItemsPresenter />
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
  <Setter Property="ItemsPanel">
    <Setter.Value>
      <ItemsPanelTemplate>
        <WrapPanel Orientation="{Binding Orientation, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Legend}}}" />
      </ItemsPanelTemplate>
    </Setter.Value>
  </Setter>
  <Setter Property="ItemTemplate">
    <Setter.Value>
      <DataTemplate DataType="{x:Type local:Series}">
        <StackPanel Orientation="Horizontal" Margin="10, 0">
          <Path Stroke="{Binding Stroke}" Fill="{Binding Fill}" Data="{Binding Converter={StaticResource seriesToGeometryConverter}}"></Path>
          <TextBlock Margin="5,0,0,0" FontFamily="{Binding TitleFontFamily}" FontSize="{Binding TitleFontSize}" Text="{Binding Title}" />
        </StackPanel>
      </DataTemplate>
    </Setter.Value>
  </Setter>
</Style>

  Here is the entire RealTimeChart template:

RealTimeChart (XAML)  Copy Code

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MindFusion.RealTimeCharting.Wpf">

    <local:ChartToLegendVisibilityConverter x:Key="chartToLegendVisibilityConverter"/>
    <local:SeriesToGeometryConverter x:Key="seriesToGeometryConverter"/>
    <local:DoubleToGridLengthConverter x:Key="doubleToGridLengthConverter"/>
    <local:DoubleToThicknessConverter x:Key="doubleToThicknessConverter"/>
    <local:PointToThicknessConverter x:Key="pointToThicknessConverter"/>
    <local:PointToStringConverter x:Key="pointToStringConverter"/>

    <Style x:Key="YAxisControl" TargetType="{x:Type ItemsControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ItemsControl}">
                    <ItemsPresenter />
                </ControlTemplate>
            </Setter.Value>
        </Setter>

        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"></StackPanel>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>

        <Setter Property="ItemTemplate">
            <Setter.Value>
                <DataTemplate DataType="{x:Type local:Axis}">
                    <local:AxisRenderer XAxis="{Binding Path=XAxis, ElementName=plotArea}" YAxis="{Binding}"></local:AxisRenderer>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style TargetType="{x:Type local:RealTimeChart}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:RealTimeChart}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid>
       <!-- add border columns and rows for spacing, bound to margins -->
                            <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" MinWidth="{TemplateBinding FrameLeftThickness}" />
                                <ColumnDefinition Width="*"></ColumnDefinition>
                                <ColumnDefinition Width="Auto" MinWidth="{TemplateBinding FrameRightThickness}"></ColumnDefinition>                               
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="{TemplateBinding FrameTopThickness, Converter={StaticResource doubleToGridLengthConverter}}"></RowDefinition>
                                <RowDefinition Height="*"></RowDefinition>
                                <RowDefinition Height="{TemplateBinding FrameBottomThickness, Converter={StaticResource doubleToGridLengthConverter}}"></RowDefinition>
                            </Grid.RowDefinitions>

       <!-- legend template -->
       <local:Legend
        x:Name="legend"
        ItemsSource="{TemplateBinding SeriesCollection}"
        Grid.Row="2" Grid.Column="1"
        Background="{TemplateBinding LegendBackground}"
        BorderBrush="{TemplateBinding LegendBorderBrush}"               
        BorderThickness="1"
        Width="{TemplateBinding LegendWidth}"
        Height="{TemplateBinding LegendHeight}"
        Orientation="{TemplateBinding LegendOrientation}"
        HorizontalAlignment="{TemplateBinding LegendHorizontalAlignment}"
        VerticalAlignment="{TemplateBinding LegendVerticalAlignment}"
        Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ShowLegend, Converter={StaticResource chartToLegendVisibilityConverter}}">
       </local:Legend>

       <!-- title template -->
       <TextBlock
        x:Name="title"
        Grid.Row="0" Grid.Column="1"
        Text="{TemplateBinding TitleText}"
        HorizontalAlignment="{TemplateBinding TitleHorizontalAlignment}"
        VerticalAlignment="{TemplateBinding TitleVerticalAlignment}"
        FontFamily="{TemplateBinding TitleFontFamily}"
        FontSize="{TemplateBinding TitleFontSize}" />

       <!-- left Y axes -->
       <ItemsControl
        Grid.Row="1" Grid.Column="0"
        Style="{StaticResource YAxisControl}"
        ItemsSource="{TemplateBinding YAxisCollection}" />

       <!-- right Y axes -->
       <ItemsControl
        Grid.Row="1" Grid.Column="2"
        Style="{StaticResource YAxisControl}"
        ItemsSource="{TemplateBinding Y2AxisCollection}" />

       <!-- plot area template -->
                            <local:PlotArea
        x:Name="plotArea"
        ClipToBounds="False"
        Grid.Column="1" Grid.Row="1"
        XAxis="{TemplateBinding XAxis}"
        SeriesCollection="{TemplateBinding SeriesCollection}"
        ScrollOffset="{TemplateBinding ScrollOffset}"
        BitmapOffset="{TemplateBinding BitmapOffset}">
       </local:PlotArea>

       <!-- tooltip template -->
                            <StackPanel
        x:Name="toolTipPanel"
        ClipToBounds="False"
        Grid.Column="1" Grid.Row="1"
        Orientation="Vertical"
        Visibility="{Binding ElementName=plotArea, Path=ToolTipVisibility}"
        Margin="{Binding ElementName=plotArea, Path=MousePosition, Converter={StaticResource pointToThicknessConverter}}">
                                <Canvas>
         <TextBlock
          x:Name="tb"
          Background="{Binding ElementName=plotArea, Path=TooltipBackground}"
          Foreground="{Binding ElementName=plotArea, Path=TooltipStroke}"
          ClipToBounds="False"
          Margin="15,0,0,0"
          Text="{Binding ElementName=plotArea, Path=DataPoint, Converter={StaticResource pointToStringConverter}, ConverterParameter='X'}" />
         <TextBlock
          Background="{Binding ElementName=plotArea, Path=TooltipBackground}"
          Foreground="{Binding ElementName=plotArea, Path=TooltipStroke}"
          ClipToBounds="False"
          Margin="{Binding ElementName=tb, Path=ActualHeight, Converter={StaticResource doubleToThicknessConverter}}"
          Text="{Binding ElementName=plotArea, Path=DataPoint, Converter={StaticResource pointToStringConverter}, ConverterParameter='Y'}" />
                                </Canvas>
                            </StackPanel>
                           
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style TargetType="{x:Type local:Legend}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:Legend}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        CornerRadius="{TemplateBinding CornerRadius}"
                        Padding="{TemplateBinding Padding}"
                        Background="{TemplateBinding Background}"
                        Margin="{TemplateBinding Margin}">
                        <ItemsPresenter />
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>

        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <WrapPanel Orientation="{Binding Orientation, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Legend}}}"/>
                </ItemsPanelTemplate>
               </Setter.Value>
        </Setter>

        <Setter Property="ItemTemplate">
            <Setter.Value>
                <DataTemplate DataType="{x:Type local:Series}">
                    <StackPanel Orientation="Horizontal" Margin="10, 0">                        
                        <Path Stroke="{Binding Stroke}" Fill="{Binding Fill}" Data="{Binding Converter={StaticResource seriesToGeometryConverter}}">
                        </Path>
                        <TextBlock Margin="5,0,0,0" FontFamily="{Binding TitleFontFamily}" FontSize="{Binding TitleFontSize}" Text="{Binding Title}"/>
                    </StackPanel>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>       
</ResourceDictionary>