Wednesday, December 10, 2008

WPF Fisheye Control

If you are a big fan of Apple - Mac OS X Leopard, you will love this WPF animated dashboard that I've created.

I was inspired to build a control (Fish Eye effect) that would mimic the dashboard of the Mac's.

This is a simple implementation of the Fish Eye control:

<Controls:FishEyeControl VerticalAlignment="Bottom">
<Image Source="{Binding Source={x:Static Images:ImageConstants.MESSAGES}}"
Width="32"
Height="32" />
<Image Source="{Binding Source={x:Static Images:ImageConstants.CONTACTS}}"
Width="32"
Height="32" />
<Image Source="{Binding Source={x:Static Images:ImageConstants.CALENDAR}}"
Width="32"
Height="32" />
</Controls:FishEyeControl>

This is a dynamic implementation (ItemsControl) of the Fish Eye control:

<ItemsControl ItemsSource="{Binding Path=DashBoardApps}" VerticalAlignment="Bottom" HorizontalAlignment="Center">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Controls:FishEyeControl />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock x:Name="txtAppName"
Text="{Binding Path=ApplicationName}"
TextAlignment="Center"
Visibility="Hidden"
FontSize="7px"
Foreground="#eff7ff" />
<Button Width="32" Height="32">
<Image Source="{Binding Path=ApplicationImage}" />
</Button>
</StackPanel>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="txtAppName" Property="Visibility" Value="Visible" />
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Animated Dashboard

Please let me know if this helps you.

Monday, November 24, 2008

Can Parallel Programming Improve Performance

I love to optimize my code for performance, whenever I can.
So I wrote a simple speed test to see what works best.

I've use the new System.Threading, provided in the Parallel Extensions June 08 CTP from Microsoft and I have to said it is bloody awesome.

For example a simple for / foreach loop:

for (var item = 0; item < list.Length; item++)
{
DoSomeWork();
}

foreach (var item in list)
{
DoSomeWork();
}


This is the same example, but using a parallel for / foreach loop:
Parallel.For(0, list.Length, item => { DoSomeWork(); });

Parallel.ForEach(list, DoSomeWork);

Coding it is as easy as pie, it makes use of all the cores that your CPU has to offer.

Speed Test

Please let me know if this helps you.

Thursday, November 13, 2008

Using WPF ListView to display Complex Data Structure

I was ask @ work today, to display in a WPF List View, a list of items and within each item there are other list of items (subclass within a class).

There are lots of examples on the net to display to simple class.
But in the real world there is no simple data structure, only complex data structure.

I wrote is example to demonstrate the point.
Imagine that you have a list of movies, and each movie has a movie id, a title, a list (subclass) of images and descriptions for the movie, a list (subclass) of cast in the movie and a list (subclass) of movie recommendations.




Code:
A list of Movies

public List<Movie> MovieData

And each Movie has

public class Movie
{
public int MovieId { get; set; }
public string Title { get; set; }
public IList<MovieInfos> Infos { get; set; }
public IList<Cast> Cast { get; set; }
public IList<string> Recommendations { get; set; }
}

MovieInfos is a subclass in the Movie class

public class MovieInfos
{
public string Description { get; set; }
public ImageSource MovieImage { get; set; }
}

Xaml:
Bind the list of movies to the WPF List View

<ListView ItemsSource="{Binding Path=MovieData}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=MovieId}" Header="Movie Id" />
<GridViewColumn DisplayMemberBinding="{Binding Path=Title}" Header="Title" />
<!-- Can Bind to complex subclass -->
<GridViewColumn Header="Movie(s)">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<ItemsControl ItemsSource="{Binding Path=Infos}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image ToolTip="{Binding Path=Description}"
Source="{Binding Path=MovieImage}"
Margin="3,0,3,0"
Height="125" Width="75" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<!-- Binding with data triggers -->
<GridViewColumn Header="Cast">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<ItemsControl ItemsSource="{Binding Path=Cast}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="tbName" Text="{Binding Path=Name}"/>
<Image x:Name="imgStar"
Visibility="Collapsed"
Source="{Binding Source={x:Static constants:ImageConstants.STAR}}"
Height="16" Width="16" Margin="3,0,0,0" />
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=MainCharacter}" Value="True">
<Setter TargetName="tbName" Property="Foreground" Value="Red" />
<Setter TargetName="imgStar" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<!-- Simple binding -->
<GridViewColumn Header="Recommendations">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<ItemsControl ItemsSource="{Binding Path=Recommendations}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>

This sample demonstrates the power of WPF List View.

Using Items Control in WPF List View

Please let me know if this helps you.

Wednesday, October 29, 2008

Use LINQ to count items in a List

I wanted a way to go through a list of items and get a count for each distinct item in the list.
To do this nice and easy, I just use LINQ.

class Program
{
static void Main()
{
var cities = new List<string>
{
"Sydney",
"Perth",
"Sydney",
"Melbourne",
"Brisbane",
"Melbourne",
"Sydney"
};

var result = (from c in cities
group c by c into grouping
orderby grouping.Key ascending
select new {grouping.Key, Count = grouping.Count()});

foreach (var item in result)
{
Console.WriteLine(string.Format("City={0}, Count={1}", item.Key, item.Count));
}

Console.ReadLine();
}
}

Count items in a List using LINQ

Please let me know if this helps you.

Tuesday, September 16, 2008

Email Address Validator

I wrote this email address validation method a few months ago.
It use a regular expression to validate an email address.

public class EmailAddressValidator
{
/// <summary>
/// Regular expression, which is used to validate an email address.
/// </summary>
private const string PATTERN = @"^[a-z|0-9][a-z|0-9]*([_'-][a-z|0-9]+)*" +
@"(([.][a-z|0-9]+)+([_'-][a-z|0-9]+)*)?@" +
@"[a-z|0-9][a-z|0-9]*([-][a-z|0-9]+)*" +
@"(([.][a-z|0-9]+)+([-][a-z|0-9]+)*)$";

/// <summary>
/// Checks whether the given email address is valid.
/// </summary>
/// <param name="emailAddress">String that contains an email address.</param>
/// <returns>True, if valid email address; otherwise false.</returns>
public static bool IsValidEmailAddress(string emailAddress)
{
if (!string.IsNullOrEmpty(emailAddress))
return Regex.IsMatch(emailAddress, PATTERN, RegexOptions.IgnoreCase);
else
return false;
}
}

I wrote this unit test to validate that the function will pass for all email that I think should be valid and invalid.

/// <summary>
/// Summary description for UnitTest
/// </summary>
[TestClass]
public class UnitTest
{
string _emailAddress;
bool _result;

[TestMethod]
public void ValidEmailAddressNormal()
{
_emailAddress = "a@b.c";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsTrue(result, _emailAddress);

_emailAddress = "joe@home.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsTrue(result, _emailAddress);

_emailAddress = "joe.bob123@home.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsTrue(result, _emailAddress);

_emailAddress = "123joe@home.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsTrue(result, _emailAddress);

_emailAddress = "joe.bob@home.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsTrue(result, _emailAddress);

_emailAddress = "joe.bob@his.home.place";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsTrue(result, _emailAddress);

_emailAddress = "duke_me.baby@hotmail.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsTrue(result, _emailAddress);

_emailAddress = "o'reilly@there.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsTrue(result, _emailAddress);

_emailAddress = "uat-test.me@hotmail123.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsTrue(result, _emailAddress);

_emailAddress = "joe_bob@jb-test.com.au";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsTrue(result, _emailAddress);

_emailAddress = "duty.it.sit.dev.prog@test.com.au";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsTrue(result, _emailAddress);

_emailAddress = "joe.bob@google.it.com.au";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsTrue(result, _emailAddress);

_emailAddress = "joe.bob@123.test.me.co.uk";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsTrue(result, _emailAddress);
}

[TestMethod]
public void InValidEmailAddressNormal()
{
_emailAddress = "joe";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "joe@home";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "joe-bob[at]home.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "joe.@bob.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = ".joe@bob.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "joe@.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "joe..bob@bob.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "joe<>bob@bob.come";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "joe~bob@bob.come";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "joe&bob@bob.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "~joe@bob.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "joe$bob@bob.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "joe+bob@bob.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "joe_bob@hotmail..com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "joe_bob@hotmail...com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "email withspace@hotmail.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "test@hot_mail.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);

_emailAddress = "test@o'reilly.com";
result = EmailAddressValidator.IsValidEmailAddress(_emailAddress);
Assert.IsFalse(result, _emailAddress);
}
}

Email Address Validator

Please let me know if this helps you.

Thursday, September 11, 2008

WPF drop down and split button

I've been trying to create a drop down button and a split button in WPF.
It has been very frustrating, but I think I finally got it.

Drop Down and Split Button ver 1.2

I have updated the split button control to use command binding.

Please let me know if this helps you.