Tuesday, 30 October 2012

Silverlight Data Templates

For this blog post I’m going to show an example of using data templates to swap in xaml depending on data.

image

This list displays 4 “Messages” each of a different “MessageType” value.  A data template is displayed depending on the MessageType.

<UserControl x:Class="UIMessage.MainPage"
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"
xmlns:UIMessage="clr-namespace:UIMessage"
mc:Ignorable="d">
<UserControl.Resources>

</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<ItemsControl x:Name="MessageList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<UIMessage:MessageDataTemplateSelector Content="{Binding}" Margin="10"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>


using System.Collections.Generic;

namespace UIMessage
{
public partial class MainPage
{
public MainPage()
{
InitializeComponent();

this.MessageList.ItemsSource = new List<Message>(4)
{
new Message() {MessageType = MessageType.Info, Text = "For your info, this is a message", Title = "INFORMATION"},
new Message() {MessageType = MessageType.Success, Text = "Well done, you're a winner!", Title = "SUCCESS!"},
new Message() {MessageType = MessageType.Error, Text = "Output your error message here", Title = "ERROR"},
new Message() {MessageType = MessageType.Question, Text = "Why?", Title = "QUESTION"}
};
}
}
}



using System;
using System.Windows;
using System.Windows.Controls;


namespace UIMessage
{
public class MessageDataTemplateSelector : ContentControl
{
protected override void OnContentChanged(object oldContent, object newContent)
{
base.OnContentChanged(oldContent, newContent);

var item = newContent as Message;
if (item==null) throw new Exception("Expected datatype is Message");

// you could load dynamically from a DLL or loose xaml file, here we use an application resource
var key = string.Format("{0}DataTemplate", item.MessageType);
var dataTemplate = Application.Current.Resources[key] as DataTemplate;

ContentTemplate = dataTemplate;
}
}
}
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Style x:Key="TextBlockStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="White" />
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontSize" Value="16" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>

<Style x:Key="PathStyle" TargetType="Path">
<Setter Property="Stroke" Value="White" />
<Setter Property="Fill" Value="White" />
<Setter Property="StrokeLineJoin" Value="Round" />
<Setter Property="Stretch" Value="Fill" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Height" Value="25" />
<Setter Property="Width" Value="25" />
</Style>

<DataTemplate x:Key="InfoDataTemplate">
<Grid Background="#D759ABC3" Height="50" Width="400">
<TextBlock Text="{Binding Text}" Style="{StaticResource TextBlockStyle}" FontSize="20" />
</Grid>
</DataTemplate>

<DataTemplate x:Key="QuestionDataTemplate">
<Grid Background="#DCF9A938" Height="150" Width="150">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>

<Path Style="{StaticResource PathStyle}" Data="M 22.1958,1.33777C 39.3958,-4.26224 59.2625,8.27112 61.7958,26.0044C 65.2625,42.9378 52.0625,60.5378 34.9958,62.2711C 18.8625,64.8044 2.4625,52.6711 0.0625,36.5378C -2.87083,21.4711 7.39583,5.4711 22.1958,1.33777 Z M 22.3292,5.4711C 11.5292,9.07111 3.2625,19.8711 3.6625,31.3378C 3.12917,46.4044 17.3958,59.8711 32.3292,58.5378C 47.3958,58.2711 60.1958,43.6044 58.1958,28.6711C 57.1292,11.7378 38.0625,-0.395569 22.3292,5.4711 Z M 24.7292,15.7378C 30.9958,11.8711 42.5958,14.6711 42.3292,23.3378C 43.1292,30.2711 34.0625,31.6044 33.3958,38.0044C 31.3958,38.0044 29.3958,38.0044 27.3958,37.8711C 27.6625,35.8711 27.7958,33.7378 28.5958,31.8711C 30.3292,29.0711 33.3958,27.3378 35.1292,24.5378C 35.3958,21.8711 33.1292,18.8044 30.1958,19.8711C 27.3958,20.2711 27.2625,23.7378 26.1958,25.7378C 23.9292,25.7378 21.6625,25.6044 19.3958,25.4711C 20.1958,21.8711 21.1292,17.7378 24.7292,15.7378 Z M 27.9292,41.6044C 29.5292,39.2044 32.5958,40.8044 34.4625,41.7378C 34.1958,43.7378 34.8625,46.8044 32.1958,47.6044C 28.7292,49.2044 25.1292,44.2711 27.9292,41.6044 Z "/>
<Path Grid.Column="1" Style="{StaticResource PathStyle}" Data="M 22.1958,1.33777C 39.3958,-4.26224 59.2625,8.27112 61.7958,26.0044C 65.2625,42.9378 52.0625,60.5378 34.9958,62.2711C 18.8625,64.8044 2.4625,52.6711 0.0625,36.5378C -2.87083,21.4711 7.39583,5.4711 22.1958,1.33777 Z M 22.3292,5.4711C 11.5292,9.07111 3.2625,19.8711 3.6625,31.3378C 3.12917,46.4044 17.3958,59.8711 32.3292,58.5378C 47.3958,58.2711 60.1958,43.6044 58.1958,28.6711C 57.1292,11.7378 38.0625,-0.395569 22.3292,5.4711 Z M 24.7292,15.7378C 30.9958,11.8711 42.5958,14.6711 42.3292,23.3378C 43.1292,30.2711 34.0625,31.6044 33.3958,38.0044C 31.3958,38.0044 29.3958,38.0044 27.3958,37.8711C 27.6625,35.8711 27.7958,33.7378 28.5958,31.8711C 30.3292,29.0711 33.3958,27.3378 35.1292,24.5378C 35.3958,21.8711 33.1292,18.8044 30.1958,19.8711C 27.3958,20.2711 27.2625,23.7378 26.1958,25.7378C 23.9292,25.7378 21.6625,25.6044 19.3958,25.4711C 20.1958,21.8711 21.1292,17.7378 24.7292,15.7378 Z M 27.9292,41.6044C 29.5292,39.2044 32.5958,40.8044 34.4625,41.7378C 34.1958,43.7378 34.8625,46.8044 32.1958,47.6044C 28.7292,49.2044 25.1292,44.2711 27.9292,41.6044 Z "/>
<Path Grid.Column="2" Style="{StaticResource PathStyle}" Data="M 22.1958,1.33777C 39.3958,-4.26224 59.2625,8.27112 61.7958,26.0044C 65.2625,42.9378 52.0625,60.5378 34.9958,62.2711C 18.8625,64.8044 2.4625,52.6711 0.0625,36.5378C -2.87083,21.4711 7.39583,5.4711 22.1958,1.33777 Z M 22.3292,5.4711C 11.5292,9.07111 3.2625,19.8711 3.6625,31.3378C 3.12917,46.4044 17.3958,59.8711 32.3292,58.5378C 47.3958,58.2711 60.1958,43.6044 58.1958,28.6711C 57.1292,11.7378 38.0625,-0.395569 22.3292,5.4711 Z M 24.7292,15.7378C 30.9958,11.8711 42.5958,14.6711 42.3292,23.3378C 43.1292,30.2711 34.0625,31.6044 33.3958,38.0044C 31.3958,38.0044 29.3958,38.0044 27.3958,37.8711C 27.6625,35.8711 27.7958,33.7378 28.5958,31.8711C 30.3292,29.0711 33.3958,27.3378 35.1292,24.5378C 35.3958,21.8711 33.1292,18.8044 30.1958,19.8711C 27.3958,20.2711 27.2625,23.7378 26.1958,25.7378C 23.9292,25.7378 21.6625,25.6044 19.3958,25.4711C 20.1958,21.8711 21.1292,17.7378 24.7292,15.7378 Z M 27.9292,41.6044C 29.5292,39.2044 32.5958,40.8044 34.4625,41.7378C 34.1958,43.7378 34.8625,46.8044 32.1958,47.6044C 28.7292,49.2044 25.1292,44.2711 27.9292,41.6044 Z "/>

<TextBlock Grid.Row="1" Text="{Binding Text}" Grid.ColumnSpan="3" Style="{StaticResource TextBlockStyle}" FontSize="20" />

<Path Grid.Row="2" Grid.Column="1" Style="{StaticResource PathStyle}" Data="M 22.1958,1.33777C 39.3958,-4.26224 59.2625,8.27112 61.7958,26.0044C 65.2625,42.9378 52.0625,60.5378 34.9958,62.2711C 18.8625,64.8044 2.4625,52.6711 0.0625,36.5378C -2.87083,21.4711 7.39583,5.4711 22.1958,1.33777 Z M 22.3292,5.4711C 11.5292,9.07111 3.2625,19.8711 3.6625,31.3378C 3.12917,46.4044 17.3958,59.8711 32.3292,58.5378C 47.3958,58.2711 60.1958,43.6044 58.1958,28.6711C 57.1292,11.7378 38.0625,-0.395569 22.3292,5.4711 Z M 24.7292,15.7378C 30.9958,11.8711 42.5958,14.6711 42.3292,23.3378C 43.1292,30.2711 34.0625,31.6044 33.3958,38.0044C 31.3958,38.0044 29.3958,38.0044 27.3958,37.8711C 27.6625,35.8711 27.7958,33.7378 28.5958,31.8711C 30.3292,29.0711 33.3958,27.3378 35.1292,24.5378C 35.3958,21.8711 33.1292,18.8044 30.1958,19.8711C 27.3958,20.2711 27.2625,23.7378 26.1958,25.7378C 23.9292,25.7378 21.6625,25.6044 19.3958,25.4711C 20.1958,21.8711 21.1292,17.7378 24.7292,15.7378 Z M 27.9292,41.6044C 29.5292,39.2044 32.5958,40.8044 34.4625,41.7378C 34.1958,43.7378 34.8625,46.8044 32.1958,47.6044C 28.7292,49.2044 25.1292,44.2711 27.9292,41.6044 Z "/>
<Path Grid.Row="2" Style="{StaticResource PathStyle}" Data="M 22.1958,1.33777C 39.3958,-4.26224 59.2625,8.27112 61.7958,26.0044C 65.2625,42.9378 52.0625,60.5378 34.9958,62.2711C 18.8625,64.8044 2.4625,52.6711 0.0625,36.5378C -2.87083,21.4711 7.39583,5.4711 22.1958,1.33777 Z M 22.3292,5.4711C 11.5292,9.07111 3.2625,19.8711 3.6625,31.3378C 3.12917,46.4044 17.3958,59.8711 32.3292,58.5378C 47.3958,58.2711 60.1958,43.6044 58.1958,28.6711C 57.1292,11.7378 38.0625,-0.395569 22.3292,5.4711 Z M 24.7292,15.7378C 30.9958,11.8711 42.5958,14.6711 42.3292,23.3378C 43.1292,30.2711 34.0625,31.6044 33.3958,38.0044C 31.3958,38.0044 29.3958,38.0044 27.3958,37.8711C 27.6625,35.8711 27.7958,33.7378 28.5958,31.8711C 30.3292,29.0711 33.3958,27.3378 35.1292,24.5378C 35.3958,21.8711 33.1292,18.8044 30.1958,19.8711C 27.3958,20.2711 27.2625,23.7378 26.1958,25.7378C 23.9292,25.7378 21.6625,25.6044 19.3958,25.4711C 20.1958,21.8711 21.1292,17.7378 24.7292,15.7378 Z M 27.9292,41.6044C 29.5292,39.2044 32.5958,40.8044 34.4625,41.7378C 34.1958,43.7378 34.8625,46.8044 32.1958,47.6044C 28.7292,49.2044 25.1292,44.2711 27.9292,41.6044 Z "/>
<Path Grid.Row="2" Grid.Column="2" Style="{StaticResource PathStyle}" Data="M 22.1958,1.33777C 39.3958,-4.26224 59.2625,8.27112 61.7958,26.0044C 65.2625,42.9378 52.0625,60.5378 34.9958,62.2711C 18.8625,64.8044 2.4625,52.6711 0.0625,36.5378C -2.87083,21.4711 7.39583,5.4711 22.1958,1.33777 Z M 22.3292,5.4711C 11.5292,9.07111 3.2625,19.8711 3.6625,31.3378C 3.12917,46.4044 17.3958,59.8711 32.3292,58.5378C 47.3958,58.2711 60.1958,43.6044 58.1958,28.6711C 57.1292,11.7378 38.0625,-0.395569 22.3292,5.4711 Z M 24.7292,15.7378C 30.9958,11.8711 42.5958,14.6711 42.3292,23.3378C 43.1292,30.2711 34.0625,31.6044 33.3958,38.0044C 31.3958,38.0044 29.3958,38.0044 27.3958,37.8711C 27.6625,35.8711 27.7958,33.7378 28.5958,31.8711C 30.3292,29.0711 33.3958,27.3378 35.1292,24.5378C 35.3958,21.8711 33.1292,18.8044 30.1958,19.8711C 27.3958,20.2711 27.2625,23.7378 26.1958,25.7378C 23.9292,25.7378 21.6625,25.6044 19.3958,25.4711C 20.1958,21.8711 21.1292,17.7378 24.7292,15.7378 Z M 27.9292,41.6044C 29.5292,39.2044 32.5958,40.8044 34.4625,41.7378C 34.1958,43.7378 34.8625,46.8044 32.1958,47.6044C 28.7292,49.2044 25.1292,44.2711 27.9292,41.6044 Z "/>
</Grid>
</DataTemplate>

<DataTemplate x:Key="SuccessDataTemplate">
<Grid Background="#E151A351" Height="100" Width="300">

<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>

<TextBlock Text="{Binding Text}" Grid.ColumnSpan="3" Style="{StaticResource TextBlockStyle}" FontSize="20" />

<TextBlock Text="{Binding Title}" Grid.Row="1" Grid.Column="1" Style="{StaticResource TextBlockStyle}" />

<Path Grid.Row="1" Style="{StaticResource PathStyle}" Data="M 22.0625,1.33466C 38.7292,-4.13202 58.1958,7.46799 61.5292,24.8013C 65.7958,42.0013 52.4625,60.5347 34.8625,62.268C 18.8625,64.8013 2.32917,52.668 0.0625,36.668C -3.00417,21.468 7.2625,5.46799 22.0625,1.33466 Z M 22.0625,5.46799C 10.8625,9.20132 2.59583,20.8013 3.52917,32.668C 3.79583,47.2013 17.6625,59.7346 32.1958,58.5347C 47.2625,58.268 60.0625,43.6013 58.0625,28.668C 56.9958,11.7346 37.9292,-0.398682 22.0625,5.46799 Z M 41.7958,17.6013C 43.3958,18.668 47.7958,19.868 45.7958,22.4013C 39.9292,29.7346 34.4625,37.6013 28.1958,44.5347C 23.7958,40.8013 20.3292,36.268 16.3292,32.1347C 13.9292,30.1347 17.6625,28.268 18.9958,26.9347C 22.4625,29.2013 24.7292,33.068 28.0625,35.7346C 32.4625,29.468 37.3958,23.7346 41.7958,17.6013 Z "/>

<Path Grid.Row="1" Grid.Column="3" Style="{StaticResource PathStyle}" Data="M 22.0625,1.33466C 38.7292,-4.13202 58.1958,7.46799 61.5292,24.8013C 65.7958,42.0013 52.4625,60.5347 34.8625,62.268C 18.8625,64.8013 2.32917,52.668 0.0625,36.668C -3.00417,21.468 7.2625,5.46799 22.0625,1.33466 Z M 22.0625,5.46799C 10.8625,9.20132 2.59583,20.8013 3.52917,32.668C 3.79583,47.2013 17.6625,59.7346 32.1958,58.5347C 47.2625,58.268 60.0625,43.6013 58.0625,28.668C 56.9958,11.7346 37.9292,-0.398682 22.0625,5.46799 Z M 41.7958,17.6013C 43.3958,18.668 47.7958,19.868 45.7958,22.4013C 39.9292,29.7346 34.4625,37.6013 28.1958,44.5347C 23.7958,40.8013 20.3292,36.268 16.3292,32.1347C 13.9292,30.1347 17.6625,28.268 18.9958,26.9347C 22.4625,29.2013 24.7292,33.068 28.0625,35.7346C 32.4625,29.468 37.3958,23.7346 41.7958,17.6013 Z "/>

</Grid>
</DataTemplate>

<DataTemplate x:Key="ErrorDataTemplate">
<Grid Background="#D5BD3630" Height="110" Width="350">

<Grid.ColumnDefinitions>
<ColumnDefinition Width="130" />
<ColumnDefinition />
</Grid.ColumnDefinitions>

<Path Width="100" Height="100" Style="{StaticResource PathStyle}" Data="M 22.0625,1.3432C 39.2625,-4.25677 59.1292,8.14319 61.6625,26.0099C 65.1292,42.9432 51.9292,60.5432 34.8625,62.2766C 18.8625,64.8099 2.32917,52.6765 0.0625,36.5432C -3.00417,21.4766 7.2625,5.47656 22.0625,1.3432 Z M 22.0625,5.47656C 11.3958,9.07654 3.12917,19.8765 3.52917,31.3432C 2.99583,46.4099 17.2625,59.8765 32.1958,58.5432C 47.2625,58.2766 60.0625,43.6099 58.0625,28.6765C 56.9958,11.7432 37.9292,-0.390137 22.0625,5.47656 Z M 18.4625,23.3432C 19.7958,21.8765 20.9958,20.5432 22.4625,19.4766C 25.2625,22.2766 28.0625,25.0765 30.9958,27.8765C 34.0625,25.2099 36.7292,22.0099 39.9292,19.4766C 41.1292,20.8099 42.3292,22.0099 43.5292,23.3432C 40.8625,26.4099 37.6625,29.0765 35.1292,32.2766C 38.0625,34.9432 40.8625,37.8765 43.5292,40.6765C 42.3292,42.0099 41.1292,43.3432 39.9292,44.6765C 36.7292,42.0099 34.0625,38.8099 30.9958,36.1432C 27.9292,38.9432 25.2625,42.1432 21.9292,44.6765C 20.8625,43.2099 19.6625,42.0099 18.5958,40.6765C 20.9958,37.7432 23.9292,35.2099 26.5958,32.4099C 25.1292,28.8099 20.8625,26.5432 18.4625,23.3432 Z "/>

<TextBlock Grid.Column="1" Text="{Binding Title}" Style="{StaticResource TextBlockStyle}" FontSize="50" />
</Grid>
</DataTemplate>
</ResourceDictionary>

In our project we have:


imageApp.xaml Contains a reference to our DataTemplates.xaml, this makes them globally accessible to our application.


DataTemplates.xaml Contains our 4 different data templates.


MainPage.xaml Our only view.


Message.cs Class definition also contains the MessageType enum


MessageDataTemplateSelector.cs The logic to work out which data template to display.


Click on the files above to view the source or download the entire project from github.


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

Saturday, 27 October 2012

Some icons and paths

error       info       question       success

Cross

image

<?xml version="1.0" encoding="utf-8"?>
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="black">
<Path Stretch="Fill" StrokeLineJoin="Round" Stroke="#FFFFFFFF" Fill="#FFFFFFFF" Data="M 22.0625,1.3432C 39.2625,-4.25677 59.1292,8.14319 61.6625,26.0099C 65.1292,42.9432 51.9292,60.5432 34.8625,62.2766C 18.8625,64.8099 2.32917,52.6765 0.0625,36.5432C -3.00417,21.4766 7.2625,5.47656 22.0625,1.3432 Z M 22.0625,5.47656C 11.3958,9.07654 3.12917,19.8765 3.52917,31.3432C 2.99583,46.4099 17.2625,59.8765 32.1958,58.5432C 47.2625,58.2766 60.0625,43.6099 58.0625,28.6765C 56.9958,11.7432 37.9292,-0.390137 22.0625,5.47656 Z M 18.4625,23.3432C 19.7958,21.8765 20.9958,20.5432 22.4625,19.4766C 25.2625,22.2766 28.0625,25.0765 30.9958,27.8765C 34.0625,25.2099 36.7292,22.0099 39.9292,19.4766C 41.1292,20.8099 42.3292,22.0099 43.5292,23.3432C 40.8625,26.4099 37.6625,29.0765 35.1292,32.2766C 38.0625,34.9432 40.8625,37.8765 43.5292,40.6765C 42.3292,42.0099 41.1292,43.3432 39.9292,44.6765C 36.7292,42.0099 34.0625,38.8099 30.9958,36.1432C 27.9292,38.9432 25.2625,42.1432 21.9292,44.6765C 20.8625,43.2099 19.6625,42.0099 18.5958,40.6765C 20.9958,37.7432 23.9292,35.2099 26.5958,32.4099C 25.1292,28.8099 20.8625,26.5432 18.4625,23.3432 Z "/>
</Grid>

Info


image

<?xml version="1.0" encoding="utf-8"?>
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="black">
<Path Stretch="Fill" StrokeLineJoin="Round" Stroke="#FFFFFFFF" Fill="#FFFFFFFF" Data="M 22.0625,1.33777C 39.2625,-4.26221 59.1292,8.27112 61.6625,26.0045C 65.1292,42.9377 51.9292,60.5378 34.8625,62.2711C 18.8625,64.8044 2.32917,52.6711 0.0625,36.5378C -3.00417,21.4711 7.2625,5.47113 22.0625,1.33777 Z M 22.0625,5.47113C 11.3958,9.07111 3.12917,19.8711 3.52917,31.3378C 2.99583,46.4044 17.2625,59.8711 32.1958,58.5378C 47.2625,58.2711 60.0625,43.6044 58.0625,28.6711C 56.9958,11.7378 37.9292,-0.395569 22.0625,5.47113 Z M 28.3292,16.1378C 31.2625,14.9378 36.0625,15.3378 35.9292,19.3378C 35.9292,23.3378 31.2625,23.3378 28.4625,22.5378L 28.5958,21.3378C 28.5958,20.0045 28.5958,18.6711 28.4625,17.3378L 28.3292,16.1378 Z M 28.5958,21.3378C 25.7958,22.1378 25.7958,16.5378 28.4625,17.3378C 28.5958,18.6711 28.5958,20.0045 28.5958,21.3378 Z M 28.8625,26.2711C 30.9958,26.1378 32.9958,26.0045 35.1292,26.0045C 35.2625,33.6044 35.2625,41.0711 35.1292,48.6711C 32.9958,48.5378 30.9958,48.5378 28.8625,48.4044C 30.0625,48.0045 32.3292,47.3378 33.5292,47.0711C 34.3292,40.5378 34.1958,34.1378 33.5292,27.6044C 32.3292,27.3378 30.0625,26.6711 28.8625,26.2711 Z M 28.8625,26.2711C 30.0625,26.6711 32.3292,27.3378 33.5292,27.6044C 34.1958,34.1378 34.3292,40.5378 33.5292,47.0711C 32.3292,47.3378 30.0625,48.0045 28.8625,48.4044C 28.9958,41.0711 28.9958,33.6044 28.8625,26.2711 Z "/>
</Grid>


Question Mark


image

<?xml version="1.0" encoding="utf-8"?>
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="black">
<Path Stretch="Fill" StrokeLineJoin="Round" Stroke="#FFFFFFFF" Fill="#FFFFFFFF" Data="M 22.1958,1.33777C 39.3958,-4.26224 59.2625,8.27112 61.7958,26.0044C 65.2625,42.9378 52.0625,60.5378 34.9958,62.2711C 18.8625,64.8044 2.4625,52.6711 0.0625,36.5378C -2.87083,21.4711 7.39583,5.4711 22.1958,1.33777 Z M 22.3292,5.4711C 11.5292,9.07111 3.2625,19.8711 3.6625,31.3378C 3.12917,46.4044 17.3958,59.8711 32.3292,58.5378C 47.3958,58.2711 60.1958,43.6044 58.1958,28.6711C 57.1292,11.7378 38.0625,-0.395569 22.3292,5.4711 Z M 24.7292,15.7378C 30.9958,11.8711 42.5958,14.6711 42.3292,23.3378C 43.1292,30.2711 34.0625,31.6044 33.3958,38.0044C 31.3958,38.0044 29.3958,38.0044 27.3958,37.8711C 27.6625,35.8711 27.7958,33.7378 28.5958,31.8711C 30.3292,29.0711 33.3958,27.3378 35.1292,24.5378C 35.3958,21.8711 33.1292,18.8044 30.1958,19.8711C 27.3958,20.2711 27.2625,23.7378 26.1958,25.7378C 23.9292,25.7378 21.6625,25.6044 19.3958,25.4711C 20.1958,21.8711 21.1292,17.7378 24.7292,15.7378 Z M 27.9292,41.6044C 29.5292,39.2044 32.5958,40.8044 34.4625,41.7378C 34.1958,43.7378 34.8625,46.8044 32.1958,47.6044C 28.7292,49.2044 25.1292,44.2711 27.9292,41.6044 Z "/>
</Grid>


Tick




image

<?xml version="1.0" encoding="utf-8"?>
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="black">
<Path Stretch="Fill" StrokeLineJoin="Round" Stroke="#FFFFFFFF" Fill="#FFFFFFFF" Data="M 22.0625,1.33466C 38.7292,-4.13202 58.1958,7.46799 61.5292,24.8013C 65.7958,42.0013 52.4625,60.5347 34.8625,62.268C 18.8625,64.8013 2.32917,52.668 0.0625,36.668C -3.00417,21.468 7.2625,5.46799 22.0625,1.33466 Z M 22.0625,5.46799C 10.8625,9.20132 2.59583,20.8013 3.52917,32.668C 3.79583,47.2013 17.6625,59.7346 32.1958,58.5347C 47.2625,58.268 60.0625,43.6013 58.0625,28.668C 56.9958,11.7346 37.9292,-0.398682 22.0625,5.46799 Z M 41.7958,17.6013C 43.3958,18.668 47.7958,19.868 45.7958,22.4013C 39.9292,29.7346 34.4625,37.6013 28.1958,44.5347C 23.7958,40.8013 20.3292,36.268 16.3292,32.1347C 13.9292,30.1347 17.6625,28.268 18.9958,26.9347C 22.4625,29.2013 24.7292,33.068 28.0625,35.7346C 32.4625,29.468 37.3958,23.7346 41.7958,17.6013 Z "/>
</Grid>

ClickOnce deployment

Warning:  There are currently issues with ClickOnce installers running on Windows 8 click here

Within Visual Studio select your WPF Project > Properties > Publish tab

1.Set the installation folder

image

2. Click “Updates…” button and set your “Application Updates” settings then click OK:

image

3. Click the “Options…” button and set your application information:

a) For description enter all the appropriate information

image

b) Click on Deployment and enter a “Deployment web page” and select “Automatically generate….”

image

4. Now we are ready to “Publish”, so click the “Publish Wizard…” button:

a) For the first step we’ll export to our local folder then manually FTP to our web server.

image

b) The next step defaults to the installation folder you entered on the Project properties Publish tab

image

c) If your application runs offline you can accept the defaults:

image

d) We are now ready to Publish, click Finish:

image

Now upload the files from your Publish folder to your web server:

image

Friday, 26 October 2012

Fiddler HTTPS

To setup Fiddler to show HTTPS request/responses you’ll need to export your client certificate from Internet Explorer into the Fiddler directory and activate HTTPS within Fiddler.

Here is how:

Internet Explorer > Tools > Options > Content tab > Click Certificates buttons:

2

Click the Export button:

3

45

6

 

1

Sunday, 7 October 2012

File streaming to Silverlight

Requirement

Expose an end point on a web server that accepts a id value and returns a file.

Solution

screenshot

fiddler

image

using System;
using System.IO;
using System.Web;

namespace FileStreaming.Web
{
public class DownloadFile : IHttpHandler
{
private const string FilesDirectory = @"\Files\";

public void ProcessRequest(HttpContext context)
{
if (context.Request.QueryString == null || context.Request.QueryString["reportid"] == null)
{
return;
}

var reportId = int.Parse(context.Request.QueryString["reportid"]);

var filename = ConvertReportIdToFileName(reportId);

var fullPath = Path.Combine(HttpContext.Current.Server.MapPath(FilesDirectory), filename);

var contentType = GetContentType(filename);

using (var reader = new StreamReader(fullPath))
{
var result = reader.ReadToEnd();
context.Response.ContentType = contentType;
context.Response.AddHeader("content-disposition", string.Format("attachment; filename={0}", filename));
context.Response.Write(result);
}
}

private string ConvertReportIdToFileName(int reportId)
{
switch (reportId)
{
case 1:
return @"report1.xlsx";
case 2:
return @"report2.docx";
case 3:
return @"report3.pdf";
default:
throw new ArgumentException("Unknown ReportId");
}
}

private string GetContentType(string file)
{
var fileExtension = file.Substring(file.Length - 4, 4).Replace(".", "");

switch (fileExtension)
{
case "xlsx":
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

case "docx":
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";

case "pdf":
return "application/pdf";

case "json":
return "text/json";

case "xml":
return "text/xml";

default:
return "unknown";
}
}

public bool IsReusable
{
get
{
return false;
}
}
}
}

Source code


https://github.com/stevenh77/FileStreaming

Saturday, 29 September 2012

C# Synchronization

Here are four examples of synchronization, firing three pieces of work and blocking until any of the three complete:

  • Tasks
  • ManualResetEvents with a WaitHandle
  • ManualResetEvent
  • Monitor Wait and Pulse

image_thumb[3]

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Synchronisation
{
internal class Program
{
private static void Main(string[] args)
{
new TaskWaitAnyExample().Execute();
new ManualResetEventWithWaitHandle().Execute();
new ManualResetEventExample().Execute();
new MonitorWaitAndPulse().Execute();
}
}

public abstract class Example
{
protected string name = "Example";

public abstract void Execute();

protected void MethodA()
{
Console.WriteLine("{0}: Entering MethodA", name);
Thread.Sleep(20000);
Console.WriteLine("{0}: Exiting MethodA", name);
}

protected void MethodB()
{
Console.WriteLine("{0}: Entering MethodB", name);
Thread.Sleep(10000);
Console.WriteLine("{0}: Exiting MethodB", name);
}

protected void MethodC()
{
Console.WriteLine("{0}: Entering MethodC", name);
Thread.Sleep(1000);
Console.WriteLine("{0}: Exiting MethodC", name);
}
}

public class TaskWaitAnyExample : Example
{
public override void Execute()
{
name = "TaskWaitAnyExample";
Console.WriteLine("{0} (from .NET 4.0):", name);

var taskA = Task.Factory.StartNew(MethodA);
var taskB = Task.Factory.StartNew(MethodB);
var taskC = Task.Factory.StartNew(MethodC);

Console.WriteLine("Waiting for one task to finish");
Task.WaitAny(taskA, taskB, taskC);
Console.WriteLine("Signal received, time to move on{0}", Environment.NewLine);
}
}

public class ManualResetEventWithWaitHandle : Example
{
public override void Execute()
{
name = "ManualResetEventWithWaitHandle";
Console.WriteLine("{0} (from .NET 1.1):", name);

WaitHandle[] waitHandles = new WaitHandle[]
{
new ManualResetEvent(false),
new ManualResetEvent(false),
new ManualResetEvent(false)
};

ThreadPool.QueueUserWorkItem(o => { MethodA(); ((ManualResetEvent)waitHandles[0]).Set(); });
ThreadPool.QueueUserWorkItem(o => { MethodB(); ((ManualResetEvent)waitHandles[1]).Set(); });
ThreadPool.QueueUserWorkItem(o => { MethodC(); ((ManualResetEvent)waitHandles[2]).Set(); });

Console.WriteLine("Waiting for one signal that one work item has finished");
WaitHandle.WaitAny(waitHandles);
Console.WriteLine("Signal received, time to move on{0}", Environment.NewLine);
}
}

public class ManualResetEventExample : Example
{
private readonly ManualResetEvent manualResetEvent = new ManualResetEvent(false);

public override void Execute()
{
name = "ManualResetEvent";
Console.WriteLine("{0} (from .NET 1.1):", name);

ThreadPool.QueueUserWorkItem(o => { MethodA(); manualResetEvent.Set(); });
ThreadPool.QueueUserWorkItem(o => { MethodB(); manualResetEvent.Set(); });
ThreadPool.QueueUserWorkItem(o => { MethodC(); manualResetEvent.Set(); });

Console.WriteLine("Waiting for one signal that one work item has finished");
manualResetEvent.WaitOne();
Console.WriteLine("Signal received, time to move on{0}", Environment.NewLine);
}
}

public class MonitorWaitAndPulse : Example
{
readonly object locker = new object();
bool signalSent;

public override void Execute()
{
name = "Monitor Wait and Pulse";
Console.WriteLine("{0} (from .NET 1.1):", name);

ThreadPool.QueueUserWorkItem(o => DoWork(MethodA));
ThreadPool.QueueUserWorkItem(o => DoWork(MethodB));
ThreadPool.QueueUserWorkItem(o => DoWork(MethodC));

Console.WriteLine("Waiting for one signal that one work item has finished");

lock (locker)
while (!signalSent)
Monitor.Wait(locker);

Console.WriteLine("Signal received, time to move on{0}", Environment.NewLine);
}

private void DoWork(Action action)
{
action.Invoke();

lock (locker)
{
signalSent = true;
Monitor.Pulse(locker);
}
}
}
}

Thursday, 27 September 2012

Test for Generic Type

Useful helper method I found on StackOverflow

using System;
using System.Collections.Generic;

namespace TestForGenericType
{
class Program
{
static void Main(string[] args)
{
var test = new List<string>();
bool result = test.GetType().IsSubclassOfRawGeneric(typeof(List<>));

// result = true
}
}

static class ReflectionUtils
{
public static bool IsSubclassOfRawGeneric(this Type toCheck, Type baseType)
{
while (toCheck != typeof(object))
{
Type cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (baseType == cur)
{
return true;
}

toCheck = toCheck.BaseType;
}
return false;
}
}
}

Sunday, 23 September 2012

INPC Parent Child Notification

Here is a simple example of a parent listening to change notification from a child and exposing an aggregate value (or “denormalized” value in database terminology).

The Order (parent) exposes the TotalCost, which is a sum of the Cost properties in OrderLines (child).

image

public class Order : InpcBase
{
private readonly ObservableCollection<OrderLine> orderLines;

public Order()
{
orderLines = new ObservableCollection<OrderLine>();
}

public decimal TotalCost
{
get { return orderLines.Sum(ol => ol.Cost); }
}

public void AddOrderLine(OrderLine orderLine)
{
orderLine.PropertyChanged += orderLine_PropertyChanged;
}

private void orderLine_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Cost") OnPropertyChanged("TotalCost");
}
}

public class OrderLine : InpcBase
{
private decimal cost;
public decimal Cost
{
get { return cost; }
set
{
if (cost == value) return;
cost = value;
OnPropertyChanged("Cost");
}
}
}

public abstract class InpcBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler == null) return;
handler(this, new PropertyChangedEventArgs(name));
}
}

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