Saturday 28 July 2012

Silverlight Metro Time Line Control

I’ve come up with a nice little user control that plots “activities” over the past couple of days.

And when I say I’ve come up with, I mean I was inspired by/copied the design from the new Microsoft Dynamics software.

It’s currently making use of the Telerik chart controls, as that’s what I am using at work but I’m sure that part could be swapped out for a Silverlight Toolkit chart.

image

Timeline.xaml

<UserControl x:Class="FxChart.TimelinePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:chart="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Charting"
xmlns:charting="clr-namespace:Telerik.Windows.Controls.Charting;assembly=Telerik.Windows.Controls.Charting"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FxChart"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
d:DesignHeight="300"
d:DesignWidth="400"
mc:Ignorable="d">
<UserControl.Resources>
<Color x:Key="BlueColor">#1BA1E2</Color>
<Color x:Key="LightBlueColor">#FFB2E0F4</Color>
<Color x:Key="LightGreyColor">#ffc9c8c8</Color>
<Color x:Key="GreyColor">#ff6d6d6d</Color>
<SolidColorBrush x:Key="BlueBrush" Color="{StaticResource BlueColor}" />
<SolidColorBrush x:Key="LightBlueBrush" Color="{StaticResource LightBlueColor}" />
<SolidColorBrush x:Key="LightGrayBrush" Color="{StaticResource LightGreyColor}" />
<SolidColorBrush x:Key="GrayBrush" Color="{StaticResource GreyColor}" />

<Style x:Key="CustomPointMark" TargetType="telerik:PointMark">
<Setter Property="Height" Value="25" />
<Setter Property="Width" Value="15" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="telerik:PointMark">
<Canvas>
<Path x:Name="PART_PointMarkPath"
Canvas.Left="{TemplateBinding PointMarkCanvasLeft}"
Canvas.Top="{TemplateBinding PointMarkCanvasTop}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Data="M198.5,96.5 C142.16696,96.5 96.5,142.16696 96.499992,198.5 C96.5,254.83304 142.16696,300.5 198.5,300.5 C254.83304,300.5 300.5,254.83304 300.5,198.5 C300.5,142.16696 254.83304,96.5 198.5,96.5 z M200.5,0.5 C310.95694,0.5 400.5,90.04306 400.5,200.5 C400.5,266.0838 368.93259,324.29465 320.16318,360.76709 L319.90009,360.95898 L202.78197,561.74298 L92.60006,368.92462 L88.678093,366.34314 C35.477753,330.4017 0.49999619,269.53558 0.5,200.5 C0.49999619,90.04306 90.043045,0.5 200.5,0.5 z"
Fill="{TemplateBinding Fill}"
Stretch="Fill"
Stroke="{TemplateBinding Stroke}"
StrokeLineJoin="Round"
StrokeThickness="{TemplateBinding StrokeThickness}"
Style="{TemplateBinding ShapeStyle}" />
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style x:Key="SeriesItemLabelStyle" TargetType="telerik:SeriesItemLabel">
<Setter Property="FontSize" Value="12" />
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Padding" Value="2,0" />
<Setter Property="IsHitTestVisible" Value="False" />
<Setter Property="Foreground" Value="Gray" />
<Setter Property="LabelStyle">
<Setter.Value>
<Style TargetType="Border">
<Setter Property="BorderThickness" Value="0" />
</Style>
</Setter.Value>
</Setter>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}" TextAlignment="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource TemplatedParent}}" />
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="telerik:SeriesItemLabel">
<Canvas x:Name="PART_MainContainer">
<ContentPresenter Margin="{TemplateBinding Padding}" />
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style x:Key="RectangleStyle" TargetType="Rectangle">
<Setter Property="Margin" Value="0,0,-1,0" />
<Setter Property="Stroke" Value="{StaticResource LightGrayBrush}" />
<Setter Property="StrokeThickness" Value="1" />
<Setter Property="Fill" Value="Transparent" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>

<Style x:Key="EndRectangleStyle" TargetType="Rectangle">
<Setter Property="Margin" Value="0,0,0,0" />
<Setter Property="Stroke" Value="{StaticResource BlueBrush}" />
<Setter Property="StrokeThickness" Value="1" />
<Setter Property="Fill" Value="{StaticResource BlueBrush}" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>

<Style x:Key="DateTextBlockStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource GrayBrush}" />
<Setter Property="FontSize" Value="12" />
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontWeight" Value="ExtraBold" />
</Style>
</UserControl.Resources>

<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Margin="100">
<chart:RadChart x:Name="RadChart1"
Height="80"
BorderThickness="0" />

<Grid Margin="0,-2,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<Grid.RowDefinitions>
<RowDefinition Height="40" />
</Grid.RowDefinitions>

<Rectangle Grid.Column="0" Style="{StaticResource EndRectangleStyle}" />
<Rectangle Grid.Column="1"
Margin="-1,0,-1,0"
Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="2" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="3" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="4" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="5" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="6" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="7" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="8" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="9" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="10" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="11" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="12" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="13" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="14" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="15" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="16" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="17" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="18" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="19" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="20" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="21" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="22" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="23" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="24" Style="{StaticResource EndRectangleStyle}" />
<Rectangle Grid.Column="25" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="26" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="27" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="28" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="29" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="30" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="31" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="32" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="33" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="34" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="35" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="36" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="37" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="38" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="39" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="40" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="41" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="42" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="43" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="44" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="45" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="46" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="47" Style="{StaticResource RectangleStyle}" />
<Rectangle Grid.Column="48" Style="{StaticResource EndRectangleStyle}" />
</Grid>

<Grid>
<TextBlock x:Name="YesterdayTextBlock"
Margin="10,0,0,0"
HorizontalAlignment="Left"
Style="{StaticResource DateTextBlockStyle}" />
<TextBlock x:Name="TodayTextBlock"
Margin="10,0,0,0"
HorizontalAlignment="Center"
Style="{StaticResource DateTextBlockStyle}" />
<TextBlock x:Name="TomorrowTextBlock"
Margin="0,0,10,0"
HorizontalAlignment="Right"
Style="{StaticResource DateTextBlockStyle}" />
</Grid>

</StackPanel>
</Grid>

</UserControl>


Timeline.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.Charting;

namespace FxChart
{
public partial class TimelinePage
{
public TimelinePage()
{
InitializeComponent();
InitializeChart();
InitializeDateLabels();
}

private void InitializeDateLabels()
{
this.YesterdayTextBlock.Text = DateTime.Today.AddDays(-1).ToString("dd.MM.yyyy");
this.TodayTextBlock.Text = DateTime.Today.ToString("dd.MM.yyyy");
this.TomorrowTextBlock.Text = DateTime.Today.AddDays(1).ToString("dd.MM.yyyy");
}

private void InitializeChart()
{
this.RadChart1.LayoutUpdated += this.RadChart1_LayoutUpdated;

var seriesMapping = GetLineSeries();
RadChart1.SeriesMappings.Add(seriesMapping);

RadChart1.Background = new SolidColorBrush(Colors.Transparent);
RadChart1.DefaultView.ChartLegend.Visibility = Visibility.Collapsed;
RadChart1.DefaultView.ChartArea.Padding= new Thickness(0);

AxisX axisX = new AxisX()
{
AutoRange = false,
IsDateTime = true,
Visibility = Visibility.Collapsed,
MinValue = DateTime.Today.AddDays(-1).ToOADate(),
MaxValue = DateTime.Today.AddDays(1).ToOADate()
};

RadChart1.DefaultView.ChartArea.AxisX = axisX;

AxisY axisY = new AxisY()
{
AutoRange = false,
IsZeroBased = true,
Visibility = Visibility.Collapsed,
MinValue = 0,
MaxValue = 4,
StripLinesVisibility = Visibility.Collapsed
};

RadChart1.DefaultView.ChartArea.AxisY = axisY;
RadChart1.ItemsSource = GetData();
}

void RadChart1_LayoutUpdated(object sender, EventArgs e)
{
var labelsPanel = this.RadChart1.FindChildByType<LabelsPanel>();
if (labelsPanel == null || labelsPanel.Children.Count == 0)
return;

this.RadChart1.LayoutUpdated -= this.RadChart1_LayoutUpdated;

foreach (SeriesItemLabel seriesItemLabel in labelsPanel.Children)
{
double leftAdjustment = -(seriesItemLabel.ActualWidth / 2 + 20);
seriesItemLabel.Margin = new Thickness(leftAdjustment, -40, 0, 0);
}
}

private SeriesMapping GetLineSeries()
{
Style pathStyle = new Style(typeof (Path));
//pathStyle1.Setters.Add(new Setter(Shape.StrokeDashArrayProperty, "1"));
pathStyle.Setters.Add(new Setter(Shape.StrokeThicknessProperty, 0));

Style lineStyle = new Style(typeof (SelfDrawingSeries));
lineStyle.Setters.Add(new Setter(SelfDrawingSeries.BorderLineStyleProperty, pathStyle));

SeriesMapping seriesMapping = new SeriesMapping();
seriesMapping.ItemMappings.Add(new ItemMapping("YValue", DataPointMember.YValue));
seriesMapping.ItemMappings.Add(new ItemMapping("ActivityDateTime", DataPointMember.XValue));
seriesMapping.ItemMappings.Add(new ItemMapping("LabelTime", DataPointMember.Label));

var lineDefinition = new LineSeriesDefinition() { SeriesStyle = lineStyle, ShowItemLabels = true, ShowPointMarks = true};
lineDefinition.Appearance.PointMark.Fill = this.Resources["BlueBrush"] as SolidColorBrush;
lineDefinition.PointMarkItemStyle = this.Resources["CustomPointMark"] as Style;

lineDefinition.SeriesItemLabelStyle = this.Resources["SeriesItemLabelStyle"] as Style;
seriesMapping.SeriesDefinition = lineDefinition;

return seriesMapping;
}

private IList<TimelineData> GetData()
{
return new List<TimelineData>(10)
{
new TimelineData() {ActivityDateTime = DateTime.Today.AddHours(-16), YValue = 1},
new TimelineData() {ActivityDateTime = DateTime.Today.AddHours(-12), YValue = 1},
new TimelineData() {ActivityDateTime = DateTime.Today.AddHours(-8), YValue = 1},
new TimelineData() {ActivityDateTime = DateTime.Today.AddHours(-4), YValue = 1},
new TimelineData() {ActivityDateTime = DateTime.Today.AddHours(8), YValue = 1},
new TimelineData() {ActivityDateTime = DateTime.Today.AddHours(10), YValue = 1},
new TimelineData() {ActivityDateTime = DateTime.Today.AddHours(12), YValue = 1},
new TimelineData() {ActivityDateTime = DateTime.Today.AddHours(16), YValue = 1},
};
}
}

public class TimelineData
{
public int YValue { get; set; }
public DateTime ActivityDateTime { get; set; }

public string LabelTime { get { return ActivityDateTime.ToString("h tt"); } }
}
}

Source


You can download the source:  https://github.com/stevenh77/FxChart


Before you run the application, make sure the RootVisual in the App.xaml.cs file is set to the TimelinePage object.


Telerik Controls


You can download a trial copy of the Telerik controls:  http://www.telerik.com/products/silverlight/overview.aspx

No comments:

Post a Comment