Tuesday, 28 August 2012

Silverlight Metro Context Menu

Here is a quick example project for creating a Silverlight Metro styled Context Menu.

Live Demo:   http://stevenhollidge.com/blog-source-code/metrocontextmenu

<Application x:Class="MetroContextMenu.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">
<Application.Resources>
<Style TargetType="toolkit:ContextMenu">
<Setter Property="Background" Value="White" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="Padding" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="toolkit:ContextMenu">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="2">
<Grid>
<ItemsPresenter Margin="{TemplateBinding Padding}" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style TargetType="toolkit:MenuItem">
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontSize" Value="14" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Padding" Value="20,2,20,2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="toolkit:MenuItem">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0"
Storyboard.TargetName="Presenter"
Storyboard.TargetProperty="Opacity"
To="0.1" />
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Unfocused" />
<VisualState x:Name="Focused">
<Storyboard>
<DoubleAnimation Duration="0"
Storyboard.TargetName="Bg"
Storyboard.TargetProperty="Opacity"
To="1" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle x:Name="Bg"
Fill="#34C5EBFF"
Opacity="0"
Stroke="#8071CBF1"
StrokeThickness="1" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>

<ContentPresenter x:Name="Presenter"
Margin="{TemplateBinding Padding}"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}" />
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace MetroContextMenu
{
public class TextBoxCutCopyPasteContextMenuBehavior : Behavior<TextBox>
{
private readonly ContextMenu contextMenu;
private readonly MenuItem copyMenuItem;
private readonly MenuItem cutMenuItem;
private readonly MenuItem pasteMenuItem;

public TextBoxCutCopyPasteContextMenuBehavior()
{
contextMenu = new ContextMenu();

cutMenuItem = new MenuItem { Header = "Cut" };
cutMenuItem.Click += CutClick;
contextMenu.Items.Add(cutMenuItem);

copyMenuItem = new MenuItem { Header = "Copy" };
copyMenuItem.Click += CopyClick;
contextMenu.Items.Add(copyMenuItem);

pasteMenuItem = new MenuItem { Header = "Paste" };
pasteMenuItem.Click += PasteClick;
contextMenu.Items.Add(pasteMenuItem);
}

void PasteClick(object sender, RoutedEventArgs e)
{
AssociatedObject.SelectedText = Clipboard.GetText();
contextMenu.IsOpen = false;
}

void CutClick(object sender, RoutedEventArgs e)
{
Clipboard.SetText(AssociatedObject.SelectedText);
AssociatedObject.SelectedText = string.Empty;
AssociatedObject.Focus();
contextMenu.IsOpen = false;
}

void CopyClick(object sender, RoutedEventArgs e)
{
Clipboard.SetText(AssociatedObject.SelectedText);
AssociatedObject.Focus();
contextMenu.IsOpen = false;
}

protected override void OnAttached()
{
AssociatedObject.MouseRightButtonDown += AssociatedObject_MouseRightButtonDown;
AssociatedObject.MouseRightButtonUp += AssociatedObjectMouseRightButtonUp;
AssociatedObject.SetValue(ContextMenuService.ContextMenuProperty, contextMenu);
base.OnAttached();
}

void AssociatedObjectMouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
pasteMenuItem.IsEnabled = Clipboard.ContainsText();

if (string.IsNullOrEmpty(AssociatedObject.SelectedText))
{
cutMenuItem.IsEnabled = false;
copyMenuItem.IsEnabled = false;
}
else
{
cutMenuItem.IsEnabled = true;
copyMenuItem.IsEnabled = true;
}

contextMenu.IsOpen = true;
}

void AssociatedObject_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}

protected override void OnDetaching()
{
AssociatedObject.MouseRightButtonDown -= AssociatedObject_MouseRightButtonDown;
AssociatedObject.MouseRightButtonUp -= AssociatedObjectMouseRightButtonUp;
base.OnDetaching();
}
}
}

Source code:  https://github.com/stevenh77/MetroContextMenu

Friday, 3 August 2012

LINQ Outer Joins

image
using System;
using System.Linq;

namespace LinqPlay
{
class Program
{
static void Main(string[] args)
{
// REQUIREMENT: Using linq show all beverages for all days
// including days where beverages have zero count

// Enum beverages: Coke, Fanta, Lilt, Sprite
// Date range: yesterday, today and tomorrow
// Stats data: 3 cokes, 1 sprite yesterday
// 1 sprite, 4 Fanta today

// SETUP THE COLLECTIONS OF DATA

string[] beverages = Enum.GetNames(typeof(Beverages));

DateTime yesterday = DateTime.Today.AddDays(-1);
DateTime today = DateTime.Today;
DateTime tomorrow = DateTime.Today.AddDays(1);

DateTime[] dates = new[] { yesterday, today, tomorrow };

var stats = new []
{
new ChartData() {Text = "Coke", Timestamp = yesterday, Value = 3},
new ChartData() {Text = "Sprite", Timestamp = yesterday, Value = 1},
new ChartData() {Text = "Sprite", Timestamp = today, Value = 1},
new ChartData() {Text = "Fanta", Timestamp = today, Value = 4}
};

// JOIN THE DATA

var qry = (from x in (from b in beverages
from d in dates
select new ChartData() {Text = b, Timestamp = d.Date})
join s in stats on new { x.Text, x.Timestamp} equals new { s.Text, s.Timestamp }
into temp1 from temp2 in temp1.DefaultIfEmpty()
select new ChartData()
{
Text = x.Text,
Timestamp = x.Timestamp,
Value = (temp2 == null ? 0 : temp2.Value)
})
.OrderBy(x => x.Timestamp).ThenBy(x => x.Text);

foreach (var chartData in qry)
{
Console.WriteLine(chartData.ToString());
}
}

enum Beverages
{
Coke,
Lilt,
Fanta,
Sprite
}

class ChartData
{
public string Text { get; set; }
public DateTime Timestamp { get; set; }
public int Value { get; set; }

public override string ToString()
{
return string.Format("{0}\t{1}\t{2}", Timestamp.ToString("dd/MM/yyyy"), Text, Value);
}
}
}
}

Enum description attribute

image
using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;

namespace EnumPlay
{
enum Position
{
[Description("Last line of defence, always crazy")]
Goalie = 0,

[Description("Big fast and love getting stuck in")]
Defender,

[Description("Play makers and tough tacklers")]
Midfielder,

[Description("Goalscorer for the team")]
Forward
}

public static class EnumExtensions
{
public static string GetDescription(this Enum value)
{
FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
DescriptionAttribute attribute = Attribute.GetCustomAttribute(fieldInfo, typeof(DescriptionAttribute)) as DescriptionAttribute;
return attribute == null ? value.ToString() : attribute.Description;
}
}

class Program
{
static void Main(string[] args)
{
OutputValues();
OutputNames();
OutputDescriptions();
}

private static void OutputValues()
{
Console.WriteLine("Values");

var values = Enum.GetValues(typeof(Position));

foreach (int value in values)
{
Console.WriteLine("\t{0}", value);
}

Console.WriteLine();
}

private static void OutputNames()
{
Console.WriteLine("Names");

var names = Enum.GetNames(typeof(Position));

foreach (string name in names)
{
Console.WriteLine("\t{0}", name);
}

Console.WriteLine();
}


private static void OutputDescriptions()
{
Console.WriteLine("Descriptions");

var enums = Enum.GetValues(typeof(Position)).Cast<Position>(); ;

foreach (Position item in enums)
{
var description = item.GetDescription();
Console.WriteLine("\t{0}", description);
}

Console.WriteLine();
}
}
}

Silverlight's missing methods

public static class Enums
{
//EXAMPLE USAGE:
// string[] names = Enums.GetNames<Position>();
public static string[] GetNames<T>()
{
var type = typeof(T);

if (!type.IsEnum) throw new ArgumentException("Type '" + type.Name + "' is not an enum");

return (from field in type.GetFields(BindingFlags.Public | BindingFlags.Static)
where field.IsLiteral
select field.Name).ToArray();
}

// EXAMPLE USAGE:
// Position[] values = Enums.GetValues<Position>();
public static T[] GetValues<T>()
{
var type = typeof(T);

if (!type.IsEnum) throw new ArgumentException("Type '" + type.Name + "' is not an enum");

return (from field in type.GetFields(BindingFlags.Public | BindingFlags.Static)
where field.IsLiteral
select (T)field.GetValue(null)).ToArray();
}

// EXAMPLE USAGE:
// Position position = Position.Goalie;
// string description = position.GetDescription();
public static string GetDescription(this Enum e)
{
FieldInfo fieldInfo = e.GetType().GetField(e.ToString());
DescriptionAttribute attribute = Attribute.GetCustomAttribute(fieldInfo, typeof(DescriptionAttribute)) as DescriptionAttribute;
return attribute == null ? e.ToString() : attribute.Description;
}

// EXAMPLE USAGE:
// string[] descriptions = Enums.GetDescriptions<Position>();
public static string[] GetDescriptions<T>()
{
var type = typeof(T);

if (!type.IsEnum) throw new ArgumentException("Type '" + type.Name + "' is not an enum");

var enums = GetValues<T>();
return (from enumeration in enums
select (enumeration as Enum).GetDescription())
.ToArray();
}
}

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

Tuesday, 17 July 2012

Metro style Slider

I was recently asked to include 3 combo boxes on a data entry screen, each with a fixed number of items.

The additional clicks to open the combo then scroll down to select the desired item seemed inefficient, when all the user wanted to do was answer the three questions then click the submit/next button.  Rapid and quick fire were the order of the day!

So I came up with a slider with text descriptions so that the user can click either the slider or the text to make their selection.  Obviously it takes up quite a bit more space but by coming up with a Metro style, which pays homage to the Telerik Slider style, it makes for quite a pleasant looking metro interface.

I’ve coded this up in Silverlight 4 but it also works in Silverlight 5.

The solution can be upgraded from fixed hardcoded values to a dynamic data driven items source, which would require auto resizing etc.  This would be the preferred solution but for now this quick solution does the trick!

Online Demo

Slider Style

For this example project the slider style is stored in the App.xaml file:

<Application x:Class="MetroSlider_SL4.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Application.Resources>
<Style x:Key="MetroThumbStyle" TargetType="Thumb">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Grid Background="#FF319FFD" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="MetroSliderStyle" TargetType="Slider">
<Setter Property="Maximum" Value="10" />
<Setter Property="Minimum" Value="1" />
<Setter Property="Value" Value="1" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Slider">
<Grid x:Name="Root">
<Grid.Resources>
<ControlTemplate x:Key="RepeatButtonTemplate">
<Grid x:Name="Root"
Background="Transparent"
Opacity="0" />
</ControlTemplate>
</Grid.Resources>

<Grid x:Name="VerticalTemplate" Visibility="Visible">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<Rectangle Grid.Row="0"
Grid.RowSpan="3"
Width="6"
Margin="0,5,0,5"
Fill="#ffc8c6c6"
RadiusX="1"
RadiusY="1"
StrokeThickness="0" />
<RepeatButton x:Name="VerticalTrackLargeChangeDecreaseRepeatButton"
Grid.Row="2"
Width="18"
IsTabStop="False"
Template="{StaticResource RepeatButtonTemplate}" />
<Thumb x:Name="VerticalThumb"
Grid.Row="1"
Width="18"
Height="11"
IsTabStop="True"
Style="{StaticResource MetroThumbStyle}" />
<RepeatButton x:Name="VerticalTrackLargeChangeIncreaseRepeatButton"
Grid.Row="0"
Width="18"
IsTabStop="False"
Template="{StaticResource RepeatButtonTemplate}" />

</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>

Source


https://github.com/stevenh77/MetroSlider_SL4

Saturday, 30 June 2012

Async Task.Delay

Internal code for Task.Delay (.NET 4.5)

public static Task Delay(int millisecondsDelay, CancellationToken cancellationToken)
{
if (millisecondsDelay < -1)
{
throw new ArgumentOutOfRangeException("millisecondsDelay", Environment.GetResourceString("Task_Delay_InvalidMillisecondsDelay"));
}
if (cancellationToken.IsCancellationRequested)
{
return FromCancellation(cancellationToken);
}
if (millisecondsDelay == 0)
{
return CompletedTask;
}
DelayPromise state = new DelayPromise(cancellationToken);
if (cancellationToken.CanBeCanceled)
{
state.Registration = cancellationToken.InternalRegisterWithoutEC(delegate (object state) {
((DelayPromise) state).Complete();
}, state);
}
if (millisecondsDelay != -1)
{
state.Timer = new Timer(delegate (object state) {
((DelayPromise) state).Complete();
}, state, millisecondsDelay, -1);
state.Timer.KeepRootedWhileScheduled();
}
return state;
}

The following examples were taken from samples within LinqPad 4.


How to implement Task.Delay in 4.0

/* You can write Task-based asynchronous methods by utilizing a TaskCompletionSource.
A TaskCompletionSource gives you a 'slave' Task that you can manually signal.
Calling SetResult() signals the task as complete, and any continuations kick off. */

void Main()
{
for (int i = 0; i < 10000; i++)
{
Task task = Delay (2000);
task.ContinueWith (_ => "Done".Dump());
}
}

Task Delay (int milliseconds) // Asynchronous NON-BLOCKING method
{
var tcs = new TaskCompletionSource<object>();
new Timer (_ => tcs.SetResult (null)).Change (milliseconds, -1);
return tcs.Task;
}

How NOT to implement Task.Delay 4.0

/* Instead of using a TaskCompletionSource, you can get (seemingly) the same result by
calling Task.Factory.StartNew. This method runs a delegate on a pooled thread,
which is fine for compute-bound work. However, it's not great for I/O-bound work
because you tie up a thread, blocking for the duration of the operation! */

void Main()
{
for (int i = 0; i < 10000; i++)
{
Task task = Delay (2000);
task.ContinueWith (_ => "Done".Dump());
}
}

Task Delay (int milliseconds) // Asynchronous non-blocking wrapper....
{
return Task.Factory.StartNew (() =>
{
Thread.Sleep (2000); // ... around a BLOCKING method!
});
}

// This approach is correct for COMPUTE-BOUND operations.

Returning a Value

// There's also a generic subclass of Task called Task<TResult>. This has a Result
// property which stores a RETURN VALUE of the concurrent operation.

void Main()
{
Task<int> task = GetAnswerToLifeUniverseAndEverything();
task.ContinueWith (_ => task.Result.Dump());
}

Task<int> GetAnswerToLifeUniverseAndEverything () // We're now returning a Task of int
{
var tcs = new TaskCompletionSource<int>(); // Call SetResult with a int instead:
new Timer (_ => tcs.SetResult (42)).Change (3000, -1);
return tcs.Task;
}

// This is great, because most methods return a value of some sort!
//
// You can think of Task<int> as 'an int in the future'.

Dealing with Exceptions

// Tasks also have an Exception property for storing the ERROR should a concurrent 
// operation fail. Calling SetException on a TaskCompletionSource signals as complete
// while populating its Exception property instead of the Result property.

void Main()
{
Task<int> task = GetAnswerToLifeUniverseAndEverything();
task.ContinueWith (_ => task.Exception.InnerException.Dump());
}

Task<int> GetAnswerToLifeUniverseAndEverything()
{
var tcs = new TaskCompletionSource<int>();
new Timer (_ => tcs.SetException (new Exception ("You're not going to like the answer!"))).Change (2000, -1);
return tcs.Task;
}

Example Usage


// Kick off a download operation in the background:
Task<string> task = new WebClient().DownloadStringTaskAsync (new Uri ("http://www.albahari.com/threading"));

// Call the .ContinueWith method to tell a task to do something when it's finished.
task.ContinueWith (_ =>
{
if (task.Exception != null)
task.Exception.InnerException.Dump();
else
{
string html = task.Result;
html.Dump();
}
});

Thursday, 28 June 2012

LeanUX

Bill Scott has some interest learning's on LeanUX that he’s sharing with the community:

Worth keeping an eye on his blog or follow him on twitter.

http://looksgoodworkswell.blogspot.co.uk/2012/06/anti-patterns-for-lean-ux.html

Wednesday, 27 June 2012

Claims based Security .NET 4.5

In .NET 4.5 Microsoft have moved Claims based security into MSCorLib a central part of the .NET framework.

This move away from explicit Role based security to a Claims based model promotes a finer grain approach and a decoupling of the security rules from the application into a third party service.

Old Style Permissions

Attribute Based

[PrincipalPermission(SecurityAction.Demand, Role = "Development")]
private void DoDeveloperWork()
{
Console.WriteLine("You are a developer");
}


Inline Security

try
{
new PrincipalPermission(null, "Development").Demand();
Console.WriteLine("You are a developer");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}


Claims Based Permissions

using System;
using System.IdentityModel.Services;
using System.Security;
using System.Security.Claims;
using System.Security.Permissions;
using System.Threading;

namespace ClaimsBasedSecurityDemo
{
class CustomAuthorisationManagerExample
{
public void Execute()
{
PrintHeader();
Setup();

try
{
TestPermissionsSuccess();
TestPermissionsFail();
}
catch (SecurityException e)
{
Console.WriteLine(": " + e.Message);
}
}

[ClaimsPrincipalPermission(SecurityAction.Demand,
Operation = "Add",
Resource = "Customer")]
private void TestPermissionsSuccess()
{
Console.WriteLine("Code successfully runs!");
}

[ClaimsPrincipalPermission(SecurityAction.Demand,
Operation = "Delete",
Resource = "Customer")]
private void TestPermissionsFail()
{
Console.WriteLine("We do not get here...");
}


private void Setup()
{
var myClaim = new Claim("http://myclaims/customer", "add");
var currentIdentity = new CorpIdentity("stevenh", myClaim);
var principal = new ClaimsPrincipal(currentIdentity);
Thread.CurrentPrincipal = principal;
}

private void PrintHeader()
{
Console.WriteLine("Custom Authorisation Manager Examples");
Console.WriteLine("_____________________________________");
Console.WriteLine();
}
}
}

Custom ClaimsAuthorizationManager

using System.Security.Claims;
using System.Linq;

namespace ClaimsBasedSecurityDemo
{
class AuthorisationManager : ClaimsAuthorizationManager
{
public override bool CheckAccess(AuthorizationContext context)
{
var resource = context.Resource.First().Value;
var action = context.Action.First().Value;

// hardcoded rules could be replaced by injection or load from xml
if (resource == "Customer" && action == "Add")
{
var hasAccess = context.Principal.HasClaim("http://myclaims/customer", "add");
return hasAccess;
}

return false;
}
}
}


app.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="system.identityModel"
type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.identityModel>
<identityConfiguration>
<claimsAuthorizationManager type="ClaimsBasedSecurityDemo.AuthorisationManager, ClaimsBasedSecurityDemo" />
</identityConfiguration>
</system.identityModel>
</configuration>

The source code below gives examples of .NET security in various forms.


image


Source


https://github.com/stevenh77/ClaimsBasedSecurityDemo

Sunday, 24 June 2012

Silverlight Xbox Menu

Here is an example of the Xbox menu in Silverlight. 

This prototype lets you move between the menu sections by clicking on the menu headings bing, home, social, videos and settings.

The bing screen and metro tiles don’t fire any events, it’s just to show the look and feel and animations between states and on selection of the tiles.

Source

https://github.com/stevenh77/SilverlightXboxMenu

Updated version

This latest version contains a background image and fixes for window resizes.

Link to online demo

http://stevenhollidge.com/blog-source-code/silverlightxboxmenu2/

Source

https://github.com/stevenh77/SilverlightXboxMenu2

Saturday, 23 June 2012

Setting EventTriggers in Blend4

In Blend 3 triggers used to have its own menu which was then replaced in Blend 4 by properties on a behavior.

Because it’s easy to forget here’s a quick screenshot of how to set the event trigger:

image

Assets menu > Behaviors > Add the behaviour > Set the Properties on the behavior

Here is an example of a custom control deriving from control to set a visual state based on an event trigger.

The “SelectionBorder” has its border brush set to null but when then mouse enters it gets set to white.  Mouse leaving event sets it back to it's normal state in the Visual State Manager.

To show a contrast in styles there is also a Storyboard resource activated by the MouseLeftButtonDown event that makes the tile look as though it's been pushed down.

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:SilverlightXboxMenu.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Style TargetType="controls:MetroTile">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:MetroTile">
<Border x:Name="SelectionBorder"
Margin="1"
BorderBrush="{x:Null}"
BorderThickness="3"
Cursor="Hand"
RenderTransformOrigin="0.5,0.5">
<Border.Resources>
<Storyboard x:Name="ButtonPressStoryboard">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="SelectionBorder" Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.GlobalOffsetZ)">
<EasingDoubleKeyFrame KeyTime="0" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<CubicEase EasingMode="EaseInOut" />
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="-50">
<EasingDoubleKeyFrame.EasingFunction>
<CubicEase EasingMode="EaseInOut" />
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<CubicEase EasingMode="EaseInOut" />
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Border.Resources>
<Border.Projection>
<PlaneProjection />
</Border.Projection>
<Border.RenderTransform>
<CompositeTransform />
</Border.RenderTransform>

<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseDown" />
<VisualState x:Name="MouseOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SelectionBorder" Storyboard.TargetProperty="(Border.BorderBrush)">
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{StaticResource MetroWhiteBrush}" />
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation d:IsOptimized="True"
Duration="0"
Storyboard.TargetName="SelectionBorder"
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)"
To="1.03" />
<DoubleAnimation d:IsOptimized="True"
Duration="0"
Storyboard.TargetName="SelectionBorder"
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)"
To="1.03" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="MainContainer" Background="{StaticResource MetroGreenBrush}">

<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter" SourceObject="{Binding ElementName=SelectionBorder}">
<ei:GoToStateAction StateName="MouseOver" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave" SourceObject="{Binding ElementName=SelectionBorder}">
<ei:GoToStateAction StateName="Normal" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeftButtonDown">
<ei:ControlStoryboardAction Storyboard="{StaticResource ButtonPressStoryboard}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid x:Name="MainGrid" Background="{Binding Background, RelativeSource={RelativeSource TemplatedParent}}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>

<Image x:Name="PART_DISPLAY_ICON"
Grid.Row="0"
Margin="10,10,10,2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Source="{Binding DisplayIcon,
RelativeSource={RelativeSource TemplatedParent}}"
Stretch="None" />

<TextBlock x:Name="PART_DISPLAY_TITLE_CONTAINER"
Grid.Row="1"
Margin="10,2,10,10"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
FontFamily="/SilverlightXboxMenu;component/Fonts/Fonts.zip#Segoe UI"
FontSize="16"
Foreground="{StaticResource MetroWhiteBrush}"
Text="{Binding DisplayText,
RelativeSource={RelativeSource TemplatedParent}}"
TextWrapping="Wrap" />
</Grid>
</Border>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

Another option would have been to derive from button to get visual states up and running then edit from there.


Live Demo


Here’s a live demo, hover over and click the tiles to see the different states:


Source


https://github.com/stevenh77/SilverlightXboxMenu

Friday, 22 June 2012

Silverlight Metro Clock

To mark my moving to Switzerland and starting a new job here is a Windows 8 Metro style clock in Silverlight 4.

Bear in mind this is just to demonstrate layout and design, the clock updates every minute but not necessarily on the minute so it doesn’t run like clockwork.  Plus the wi-fi and battery icons are just for show and don’t dynamically update with actual readings.

Source

DigitalClock.xaml.cs

using System;
using System.Windows.Threading;

namespace SilverlightMetroClock
{
public partial class DigitalClock
{

public DigitalClock()
{
InitializeComponent();

// updates every minute but perhaps not on the minute :)
DispatcherTimer timer = new DispatcherTimer {Interval = new TimeSpan(0, 0, 1, 0)};
timer.Tick += timer_Tick;
timer.Start();

UpdateDisplay();
}

void timer_Tick(object sender, EventArgs e)
{
UpdateDisplay();
}

void UpdateDisplay()
{
var now = DateTime.Now;

TimeTextBlock.Text = now.ToString("HH:mm");
DayTextBlock.Text = now.ToString("dddd");
DateTextBlock.Text = now.ToString("MMMM d");
}
}
}


DigitalClock.xaml

<UserControl x:Class="SilverlightMetroClock.DigitalClock"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="500"
Height="150">

<Grid Background="{StaticResource BackgroundBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25" />
<ColumnDefinition Width="30" />
<ColumnDefinition Width="25" />
<ColumnDefinition Width="200" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<Viewbox x:Name="WifiIcon"
Grid.Row="0"
Grid.Column="1"
Height="25"
Margin="0,0,0,5"
VerticalAlignment="Bottom">
<Path Width="26"
Height="26"
Margin="0,0,0,0"
Data="M33.172937,38.270306C33.636298,38.265931 34.098408,38.31531 34.548637,38.417819 33.938327,39.957959 33.588148,41.638111 33.588148,43.398272 33.588148,45.628473 34.138429,47.718663 35.088913,49.578833 32.867781,50.43891 30.286466,49.918863 28.64563,48.058694 26.524549,45.658476 26.804692,41.968142 29.255941,39.777943 30.381515,38.780352 31.782854,38.283432 33.172937,38.270306z M42.515223,36.582736C41.955198,36.582736 41.395174,36.79527 40.970165,37.22034 40.120026,38.070478 40.120026,39.460438 40.970165,40.310577L44.15025,43.490663 41.150105,46.490808C40.300089,47.340947 40.300089,48.730907 41.150105,49.581045 42.000122,50.430941 43.390204,50.430941 44.240344,49.581045L47.240488,46.5809 50.12051,49.460922C50.980659,50.311062 52.360731,50.311062 53.210749,49.460922 54.060764,48.611028 54.070774,47.220823 53.210749,46.370685L50.330604,43.490663 53.390688,40.430457C54.240828,39.580561 54.240828,38.190357 53.390688,37.340463 52.540672,36.490324 51.150589,36.480314 50.300572,37.340463L47.240488,40.400425 44.06028,37.22034C43.635272,36.79527,43.075247,36.582736,42.515223,36.582736z M47.180427,32.67007C53.110767,32.670071 57.910927,37.470352 57.910927,43.400571 57.910927,49.331034 53.110767,54.131071 47.180427,54.131071 41.260096,54.131071 36.449927,49.331034 36.449927,43.400571 36.449927,37.470352 41.260096,32.670071 47.180427,32.67007z M33.018136,20.500918C36.1167,20.47427 39.221307,21.069399 42.202856,22.325673 46.113247,24.105708 49.633599,27.405772 53.063942,31.165845 51.283764,30.305828 49.293565,29.815819 47.183354,29.815819 44.04304,29.815819 41.15275,30.89584 38.85252,32.685874 33.091944,29.145806 28.101444,30.305828 20.820716,36.945957L20.400673,37.315964 13.629995,29.655815 14.030037,29.285808C19.4137,23.627574,26.201293,20.559546,33.018136,20.500918z M34.071325,0.0013465881C39.261796,0.043453217 44.356957,1.0763702 48.876303,3.4138107 57.485651,8.124321 62.65526,12.764826 66.664957,17.205307L58.505575,24.436091C54.71586,20.265638 50.416186,16.30521 44.456637,13.274881 32.057576,7.4142456 15.908798,12.43479 7.4394379,21.795804L7.0194702,22.185847 0,14.244986 0.42996979,13.854944C6.9197903,6.2569313,20.806787,-0.10626984,34.071325,0.0013465881z"
Fill="{StaticResource ForegroundBrush}"
Stretch="Uniform" />
</Viewbox>

<Viewbox x:Name="BatteryIcon"
Grid.Row="1"
Grid.Column="1"
Height="25"
Margin="0,5,0,0"
VerticalAlignment="Top">
<Path Width="26"
Height="26"
Margin="0,0,0,0"
Data="M5.0491318,48.393315C4.3017105,48.393315,3.6969174,48.522218,3.6969172,48.682416L3.6969172,58.229268C3.6969174,58.389474,4.3017105,58.519574,5.0491318,58.519574L21.312653,58.519574C22.059346,58.519574,22.663838,58.389474,22.663838,58.229268L22.663838,48.682416C22.663838,48.522218,22.059346,48.393315,21.312653,48.393315z M5.0491318,34.039033C4.3017105,34.039033,3.6969174,34.167933,3.6969172,34.329535L3.6969172,43.876489C3.6969174,44.035188,4.3017105,44.166688,5.0491318,44.166688L21.312653,44.166688C22.059346,44.166688,22.663838,44.035188,22.663838,43.876489L22.663838,34.329535C22.663838,34.167933,22.059346,34.039033,21.312653,34.039033z M5.0491318,19.686151C4.3017105,19.686151,3.6969174,19.815052,3.6969172,19.975152L3.6969172,29.522107C3.6969174,29.682307,4.3017105,29.813907,5.0491318,29.813907L21.312653,29.813907C22.059346,29.813907,22.663838,29.682307,22.663838,29.522107L22.663838,19.975152C22.663838,19.815052,22.059346,19.686151,21.312653,19.686151z M1.4384639,10.689999L24.397816,10.689999C25.190506,10.689999,25.835001,11.192702,25.835001,11.811106L25.835001,61.174687C25.835001,61.794492,25.190506,62.296994,24.397816,62.296994L1.4384639,62.296994C0.64354791,62.296994,3.776515E-07,61.794492,0,61.174687L0,11.811106C3.776515E-07,11.192702,0.64354791,10.689999,1.4384639,10.689999z M7.0463995,0L18.789292,0C19.762597,0,20.552,0.78900433,20.552,1.76159L20.552,5.0504084C20.552,6.0229974,19.762597,6.8119996,18.789292,6.8119998L7.0463995,6.8119998C6.0730642,6.8119996,5.2840003,6.0229974,5.2840008,5.0504084L5.2840008,1.76159C5.2840003,0.78900433,6.0730642,0,7.0463995,0z"
Fill="{StaticResource ForegroundBrush}"
Stretch="Uniform" />
</Viewbox>

<TextBlock x:Name="TimeTextBlock"
Grid.RowSpan="2"
Grid.Column="3"
Style="{StaticResource TimeTextBlockStyle}"
Text="14:38" />

<TextBlock x:Name="DayTextBlock"
Grid.Column="5"
Style="{StaticResource DayTextBlockStyle}"
Text="Saturday" />

<TextBlock x:Name="DateTextBlock"
Grid.Row="1"
Grid.Column="5"
Style="{StaticResource DateTextBlockStyle}"
Text="September 29" />
</Grid>
</UserControl>

App.xaml

<Application x:Class="SilverlightMetroClock.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<SolidColorBrush x:Key="ForegroundBrush" Color="White" />
<SolidColorBrush x:Key="BackgroundBrush" Color="#E4000000" />
<Style x:Key="TimeTextBlockStyle" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="/SilverlightMetroClock;component/Fonts/Fonts.zip#Segoe UI Light" />
<Setter Property="FontSize" Value="82" />
<Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" />
</Style>
<Style x:Key="DayTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="/SilverlightMetroClock;component/Fonts/Fonts.zip#Segoe UI Light" />
<Setter Property="FontSize" Value="32" />
<Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Margin" Value="0,0,0,-5" />
<Setter Property="VerticalAlignment" Value="Bottom" />
</Style>
<Style x:Key="DateTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="/SilverlightMetroClock;component/Fonts/Fonts.zip#Segoe UI Light" />
<Setter Property="FontSize" Value="32" />
<Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Margin" Value="0,-2,0,0" />
<Setter Property="VerticalAlignment" Value="Top" />
</Style>
</Application.Resources>
</Application>


Online Demo


http://stevenhollidge.com/blog-source-code/silverlightmetroclock/


Download Source Code


https://github.com/stevenh77/SilverlightMetroClock

Metro Bold Colors

 

bold