Relative Date Time Converter

Value converters are really what help make good applications become great, they plug into the binding infrastructure and help convert values appropriate to the model into values appropriate for the view. Being able to convert say a temperature from a simple integer into something like a SolidColourBrush gives a very easy representation of heat.

These work in all three of the xaml based frameworks, Windows Phone 7, Silverlight and WPF and because value converters are so compact they're also very testable.

A lot of sites represent days in a more interesting "5 minutes ago" format, so I set about throwing together a quick value converter for this, converting from a date to a string. I've become a big fan of using dictionaries of functions in this way for times when many if statements become too messy and a strategy style pattern is overkill.

public class RelativeDateTimeConverter : IValueConverter

{

    private const int Minute = 60;

    private const int Hour = Minute * 60;

    private const int Day = Hour * 24;

    private const int Year = Day * 365;

 

    private readonly Dictionary<long, Func<TimeSpan, string>> thresholds = new Dictionary<long, Func<TimeSpan, string>>

    {

        {2, t => "a second ago"},

        {Minute,  t => String.Format("{0} seconds ago", (int)t.TotalSeconds)},

        {Minute * 2,  t => "a minute ago"},

        {Hour,  t => String.Format("{0} minutes ago", (int)t.TotalMinutes)},

        {Hour * 2,  t => "an hour ago"},

        {Day,  t => String.Format("{0} hours ago", (int)t.TotalHours)},

        {Day * 2,  t => "yesterday"},

        {Day * 30,  t => String.Format("{0} days ago", (int)t.TotalDays)},

        {Day * 60,  t => "last month"},

        {Year,  t => String.Format("{0} months ago", (int)t.TotalDays / 30)},

        {Year * 2,  t => "last year"},

        {Int64.MaxValue,  t => String.Format("{0} years ago", (int)t.TotalDays / 365)}

    };

 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

    {

        var dateTime = (DateTime)value;

        var difference = DateTime.UtcNow - dateTime.ToUniversalTime();

 

        return thresholds.First(t => difference.TotalSeconds < t.Key).Value(difference);

    }

 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

    {

        throw new NotSupportedException();

    }

}

<TextBlock Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding Created, Converter={StaticResource RelativeDateTimeConverter}}" />

Shout It Kick It submit to reddit

Windows Phone 7 Tutorials: Isolated Storage and User Controls

The next two tutorials in the Windows Phone 7 Sample Applications have just been uploaded. They've taken a little longer to get out as I've started work on my first actual application for the Windows Phone 7, a client for the Stack Overflow family of websites. I'm also developing the example applications out of series because I'm waiting for the offical maps controls before developing applications using that.

Quick Mail allows you to store email templates to allow you to send out standard emails quickly. It demonstrates user of Isolated Storage, the Application Bar and Page Navigation.

Snowfall displays an animated snowfall you can interact with using touch events. It demonstrates creating User Controls and Manipulation Events.

Hope you enjoy.

Shout It Kick It submit to reddit

Two more WP7 tutorials

I've just upated the Windows Phone 7 Example Applications list with the next two applications. Both are a little longer, and little more complex as I try to introduce some more features. Given that both also use Expression Blend to do some of the work I've included videos on how to use Blend.

Count Me In is an app to help you keep your place while counting, it introduces the MVVM pattern, commands, binding and behaviors.

Reaction Time tests your reaction speed and brings into play the Silverlight Visual State Manager, transforms and transitions.

Hope you enjoy.

Shout It Kick It submit to reddit

Social Media Html Helpers

I'm currently in the process of writing the next to tutorials in my Windows Phone 7 tutorial series and thought I'd share these snippets of code.

public static class SocialMediaExtensions

{

    public static HtmlString DotNetShoutOut(this HtmlHelper htmlHelper, string url)

    {

        url = HttpUtility.UrlEncode(ToAbsolute(htmlHelper.ViewContext.HttpContext.Request, url));

 

        var img = new TagBuilder("img");

 

        img.Attributes["src"] = "http://dotnetshoutout.com/image.axd?url=" + url;

        img.Attributes["alt"] = "Shout It";

        img.Attributes["style"] = "border: 0px;";

        img.Attributes["width"] = "82";

        img.Attributes["height"] = "18";

 

        var a = new TagBuilder("a");

 

        a.Attributes["rev"] = "vote-for";

        a.Attributes["href"] = "http://dotnetshoutout.com/submit?url=" + url;

 

        a.InnerHtml = img.ToString(TagRenderMode.SelfClosing);

 

        return new HtmlString(a.ToString(TagRenderMode.Normal));

    }

 

    public static HtmlString DotNetKicks(this HtmlHelper htmlHelper, string url)

    {

        url = HttpUtility.UrlEncode(ToAbsolute(htmlHelper.ViewContext.HttpContext.Request, url));

 

        var img = new TagBuilder("img");

 

        img.Attributes["src"] = "http://dotnetkicks.com/services/images/kickitimagegenerator.ashx?url=" + url;

        img.Attributes["alt"] = "Kick It";

        img.Attributes["style"] = "border: 0px;";

        img.Attributes["width"] = "82";

        img.Attributes["height"] = "18";

 

        var a = new TagBuilder("a");

 

        a.Attributes["rev"] = "vote-for";

        a.Attributes["href"] = "http://dotnetkicks.com/kick/?url=" + url;

 

        a.InnerHtml = img.ToString(TagRenderMode.SelfClosing);

 

        return new HtmlString(a.ToString(TagRenderMode.Normal));

    }

 

    public static HtmlString Reddit(this HtmlHelper htmlHelper, string url)

    {

        url = HttpUtility.UrlEncode(ToAbsolute(htmlHelper.ViewContext.HttpContext.Request, url));

 

        var img = new TagBuilder("img");

 

        img.Attributes["src"] = "http://reddit.com/static/spreddit7.gif";

        img.Attributes["alt"] = "submit to reddit";

        img.Attributes["style"] = "border: 0px;";

 

        var a = new TagBuilder("a");

 

        a.Attributes["rev"] = "vote-for";

        a.Attributes["href"] = "http://reddit.com/r/programming/submit?url=" + url;

 

        a.InnerHtml = img.ToString(TagRenderMode.SelfClosing);

 

        return new HtmlString(a.ToString(TagRenderMode.Normal));

    }

 

    private static string ToAbsolute(HttpRequestBase request, string url)

    {

        if(request == null)

            throw new ArgumentNullException("request");

 

        if(url == null)

            throw new ArgumentNullException("url");

 

        var format = request.IsSecureConnection ? "https://{0}{1}" : "http://{0}{1}";

 

        return String.Format(format, request.Url.Host, url);

    }

They're pretty simple little helpers and can be used for any urls. The only thing that may need to change is the ToAbsolute method which is only for the root application. To the use the helpers in my blog I have the following.

<p>

    <%: Html.DotNetShoutOut(Url.Action("Posts", new { slug = Model.Slug.ToLower() })) %>

    <%: Html.DotNetKicks(Url.Action("Posts", new { slug = Model.Slug.ToLower() })) %>

    <%: Html.Reddit(Url.Action("Posts", new { slug = Model.Slug.ToLower() })) %>

</p>

Shout It Kick It submit to reddit

More Windows Phone 7 Tutorials

I've just posted the third and fourth tutorials in my series in recreating the AppsAmuck sample applications for Windows Phone 7. These two cover Tasks and connecting to a JSON service. Both of these show some limitations in the current WP7 SDK.

Tasks

My IP Address

You can view the full list at Windows Phone 7 Tutorials.

Shout It Kick It submit to reddit