Thursday, December 12, 2013

Pattern matching extension methods

Sometimes you need to select a subset of items in a collection based on a pattern match of one of their properties. Think "all of the people who's name starts with D" or "all of the invoices with "CREDIT" in the description".

In Sql you'd use LIKE. In .NET, for simple patterns string has StartsWith, EndsWith, Contatins. For anything more complex you'd probably resort to regular expressions. Personally I've never been a huge fan of regular expressions, though they are very powerful. The syntax is just too arcane for me to keep in my head. I can pound away at a regex and get it right, but as soon as I look away I have absolutely no idea what it is doing. For this reason I find them difficult to maintain, extend and debug. That's just me though.

LIKE on the other hand is simple to understand just by looking at. It's not as expressive as regex nor as powerful, but for everyday usage goes a long way to getting the job done when you need pattern matching.

If you are working in .Net land and using Linq to Sql, you can easily use SqlMethods.Like. If you're working with Linq to objects however you either have to use the built in methods of string or result to regex. The extension class below provides a way to also use LIKE syntax for pattern matching when you are using Linq to Objects. Under the hood, it converts the LIKE pattern to a regex pattern and uses the Regex engine to do the matching. As such it supports both regex and LIKE match queries.

I've found it handy in a couple of spots and it's basic usage is like this:

var invoices = GetInvoices();
var credits = invoices.Like(i => i.Description, "%credit%");

The Like extension will return all of the invoices objects where the description contains the word credit, case insensitively.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Text;

namespace PatternMatching
{
    public static class PatternMatchExtensions
    {
        public static IEnumerable<string> Like(this IEnumerable<string> source, string pattern)
        {
            var regex = ConvertLikeToRegex(pattern);
            return source.Match(regex, RegexOptions.IgnoreCase);
        }

        public static IEnumerable<T> Like<T>(this IEnumerable<T> source, Func<T, string> selector, string pattern)
        {
            var regex = ConvertLikeToRegex(pattern);
            return source.Match<T>(selector, regex, RegexOptions.IgnoreCase);
        }

        public static IEnumerable<T> Match<T>(this IEnumerable<T> source, string regex, RegexOptions options = RegexOptions.None)
        {
            return source.Match<T>(t => t == null ? null : t.ToString(), regex, options);
        }

        public static IEnumerable<T> Match<T>(this IEnumerable<T> source, Func<T, string> selector, string regex, RegexOptions options = RegexOptions.None)
        {
            return source.Match<T>(selector, new Regex(regex, options));
        }

        public static IEnumerable<string> Match(this IEnumerable<string> source, Regex regex)
        {
            return source.Where(s => IsMatch(s, regex));
        }

        public static IEnumerable<T> Match<T>(this IEnumerable<T> source, Func<T, string> selector, Regex regex)
        {
            return source.Where<T>(t => IsMatch(selector(t), regex));
        }

        static bool IsMatch(string input, Regex regex)
        {
            if (input == null)
                return false;

            return regex.IsMatch(input);
        }

        static string ConvertLikeToRegex(string pattern)
        {
            StringBuilder builder = new StringBuilder();
            // Turn "off" all regular expression related syntax in the pattern string
            // and add regex beginning of and end of input tokens so '%abc' and 'abc%' work as expected
            builder.Append("^").Append(Regex.Escape(pattern)).Append("$");

            /* Replace the SQL LIKE wildcard metacharacters with the
            * equivalent regular expression metacharacters. */
            builder.Replace("%", ".*").Replace("_", ".");

            /* The previous call to Regex.Escape actually turned off
            * too many metacharacters, i.e. those which are recognized by
            * both the regular expression engine and the SQL LIKE
            * statement ([...] and [^...]). Those metacharacters have
            * to be manually unescaped here. */
            builder.Replace(@"\[", "[").Replace(@"\]", "]").Replace(@"\^", "^");

            // put SQL LIKE wildcard literals back
            builder.Replace("[.*]", "[%]").Replace("[.]", "[_]");

            return builder.ToString();
        }
    }
}

Saturday, December 1, 2012

How can a portable class library not have a common http client?

Visual Studio 2012 has introduced a concept called a Portable Class Library. In theory this should allow us to write assemblies to target multiple platforms such as Windows Store apps, the Xbox, and Windows phone; reusing as much code as possible. This should leave us to only need to write platform specific code as it relates to the particulars of the UI of each of those systems.

What is odd, and what in my mind renders the whole concept almost irrelevant is that there is not an http client library shared across the major platform targets. I don't know about your code but the aside from maybe some serialization POCO types, maybe a sprinkle of business logic and perhaps some MVVM stuff, the important and complex things that need to be shared across platforms is accessing http services.

I find that supporting diverse REST services, their peculiarities and differences of authentication and authorization to be the most tedious part of writing device apps and therefore the most valuable candidate for abstraction in a class library.

But as far as I can tell if you make a PCL that targets store apps and windows phone apps you have to implement platform specific extension points to govern http access.

Silverlight and Windows phone get's the WebClient; store apps the HttpClient. I have no idea what the Xbox needs. Without a cross platform http abstraction I can't really see making much use of a PCL and will likely resort to linking source files across project types or conditional compilation directives.

Sunday, November 25, 2012

Converter to hide items when something is null or empty string

Often times in Xaml you've got some labels, or buttons that you don't want to show if something in the ViewModel is null or empty. Take the example below. The ViewModel has a nullable property rating. If it is non-null a handful of controls are rendered to show it graphically and numerically. If it is null however we don't want to see any of that stuff. This converter helps hide elements of something in the ViewModel is null or empty string.

<Grid Margin="30,0,0,0" Visibility="{Binding Location.rating, Converter={StaticResource NullToVisibilityConverter}}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0" Text="Rating" VerticalAlignment="Center" HorizontalAlignment="Center" Style="{StaticResource BasicTextStyle}"/>
    <Grid Margin="0,15,0,0" Grid.Row="1" >
        <TextBlock Text="{Binding Location.rating}" Style="{StaticResource BasicTextStyle}" HorizontalAlignment="Center" VerticalAlignment="Center" TextAlignment="Center" FontSize="24"/>
        <controls:RingSlice 
            InnerRadius="35"
            Radius="45"
            StartAngle="0"
            EndAngle="{Binding RatingAngle}"
            Fill="{Binding RatingColor}">
        </controls:RingSlice>
    </Grid>
    <TextBlock Grid.Row="2" Text="{Binding Reviews}" Margin="0,15,0,0"  Style="{StaticResource BodyTextStyle}" 
               VerticalAlignment="Stretch" HorizontalAlignment="Stretch" TextAlignment="Center"/>
</Grid>

    public sealed class NullToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            if (value is string)
                return string.IsNullOrEmpty((string)value) ? Visibility.Collapsed : Visibility.Visible;

            return object.ReferenceEquals(value, null) ? Visibility.Collapsed : Visibility.Visible;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }

Saturday, January 28, 2012

A slightly less simple object browser for windows phone 7

Building slightly on the previous post we can drill into properties and navigate back up the parent tree. The Xaml adds some styling and a couple of hyperlinks:
<UserControl x:Class="GoogleAuthDemo.ObjectBrowser"
    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:local="clr-namespace:GoogleAuthDemo"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="480" d:DesignWidth="480"
    x:Name="root">

    <UserControl.Resources>
        <local:ObjectPropertiesConverter x:Key="ObjectPropertiesConvert"/>

        <Style x:Key="PropertyStyle" TargetType="HyperlinkButton">
         <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
         <Setter Property="Background" Value="Transparent"/>
         <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMedium}"/>
         <Setter Property="Padding" Value="0"/>
         <Setter Property="Template">
          <Setter.Value>
           <ControlTemplate TargetType="HyperlinkButton">
            <Border Background="Transparent">
             <VisualStateManager.VisualStateGroups>
              <VisualStateGroup x:Name="CommonStates">
               <VisualState x:Name="Normal">
                <Storyboard>
                 <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="TextElement">
                  <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneAccentBrush}"/>
                 </ObjectAnimationUsingKeyFrames>
                </Storyboard>      
         </VisualState>
               <VisualState x:Name="MouseOver"/>
               <VisualState x:Name="Pressed">
                <Storyboard>
                 <DoubleAnimation Duration="0" To="0.5" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="TextElement"/>
                </Storyboard>
               </VisualState>
               <VisualState x:Name="Disabled">
                <Storyboard>
                 <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="TextElement">
                  <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
                 </ObjectAnimationUsingKeyFrames>
                </Storyboard>
               </VisualState>
              </VisualStateGroup>
             </VisualStateManager.VisualStateGroups>
             <Border Background="{TemplateBinding Background}" Margin="{StaticResource PhoneHorizontalMargin}" Padding="{TemplateBinding Padding}">
              <TextBlock x:Name="TextElement" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Text="{TemplateBinding Content}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
             </Border>
            </Border>
           </ControlTemplate>
          </Setter.Value>
         </Setter>
        </Style>

        <DataTemplate x:Key="PropertyTemplate">
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
                <TextBlock Text="{Binding Name}" Margin="0,0,10,1"/>
                     <HyperlinkButton HorizontalAlignment="Right" 
                    IsEnabled="{Binding HasChildren}"
                    Content="{Binding Value}"                    
                    Click="HyperlinkButton_Click" Style="{StaticResource PropertyStyle}"/>

            </StackPanel>
        </DataTemplate>
    </UserControl.Resources>

    <StackPanel Orientation="Vertical">
        <HyperlinkButton Content="< Back" Foreground="{StaticResource PhoneAccentBrush}" HorizontalAlignment="Left"
             IsEnabled="{Binding ElementName=root, Path=CanBack}"
                         Click="BackButton_Click" FontWeight="Bold" FontStyle="Normal"/>
        <ScrollViewer>
            <ItemsControl ItemTemplate="{StaticResource PropertyTemplate}"
                      ItemsSource="{Binding Path=., Converter={StaticResource ObjectPropertiesConvert}}">
            </ItemsControl>
        </ScrollViewer>
    </StackPanel>
</UserControl>

Then we need to add little bit to the control code behind to handle forward and backward navigation:
    public partial class ObjectBrowser : UserControl
    {

        public ObjectBrowser()
        {
            InitializeComponent();
        }

        private Stack<object> _backStack = new Stack<object>();

        private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
        {
            if (this.DataContext != null)
            {
                _backStack.Push(this.DataContext);
                CanBack = true;
            }
            ObjectProperty p = ((HyperlinkButton)sender).DataContext as ObjectProperty;
            if (p != null)
                this.DataContext = p.TheObject;
        }

        private void BackButton_Click(object sender, RoutedEventArgs e)
        {
            if (_backStack.Count > 0)
            {
                DataContext = _backStack.Pop();
                CanBack = _backStack.Count > 0;
            }
        }

        /// 
        /// The  dependency property's name.
        /// 
        public const string CanBackPropertyName = "CanBack";

        /// 
        /// Gets or sets the value of the 
        /// property. This is a dependency property.
        /// 
        public bool CanBack
        {
            get
            {
                return (bool)GetValue(CanBackProperty);
            }
            set
            {
                SetValue(CanBackProperty, value);
            }
        }

        /// 
        /// Identifies the  dependency property.
        /// 
        public static readonly DependencyProperty CanBackProperty = DependencyProperty.Register(
            CanBackPropertyName,
            typeof(bool),
            typeof(ObjectBrowser),
            new PropertyMetadata(false));
    }
And we still need this converter class to take an object and break out its properties into something we can enumerate over to get theproperty name and instance's value:
    public class ObjectPropertiesConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                return null;

            return from p in value.GetType().GetProperties()
                   where p.CanRead && p.GetIndexParameters().Count() == 0 // skip indexer properties
                   select new ObjectProperty
                   {
                       Name = p.Name,
                       TheObject = p.GetValue(value, null)
                   };
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
But we're going to replace the KeyValuePair with a small helper class. This is what each row in the browser will bind to and it keeps the actual object around to support navigation through the tree:
    public class ObjectProperty
    {
        public object TheObject { get; set; }
        public string Name { get; set; }
        public string Value
        {
            get
            {
                return TheObject != null ? TheObject.ToString() : "(null)";
            }
        }

        public bool HasChildren
        {
            get
            {
                if (TheObject != null)
                    return !TheObject.GetType().IsValueType;// && !(TheObject is string);

                return false;
            }
        }
    }
So with that you should be able to navigate object hierarchies from within the phone app at runtime. I wouldn't use it in an app but I'm hoping it will be good debugging and rapid prototyping tool so I can build the data layer and rought UI structure and then deal with UI styling later.
** warning - I'm posting as I code this so test coverage is well, um... limited **

A simple SilverLight object viewer

Sometimes when you're making a windows phone 7 rest client you just want to look at some of the returned data to poke see what's there. You can wire up some ui or use tracing. Maybe some breakpoints. But it's also nice to be able to drop something into the UI that you can access easily and as needed. The WinForms object browser is a handy for instance for debugging things at runtime, within the app without a debugger or a designed UI. This little widget isn't as fully functional as taht but can be helpful in a similar way. Drop it somewhere in the UI and set its DataContext property and all public readable properies will be listed with name and value. First some XAML
<UserControl x:Class="GoogleAuthDemo.ObjectBrowser"
    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:local="clr-namespace:GoogleAuthDemo"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="480" d:DesignWidth="480">
    
    <UserControl.Resources>
        <local:ObjectPropertiesConverter x:Key="ObjectPropertiesConvert"/>
        
        <DataTemplate x:Key="PropertyTemplate">
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
                <TextBlock Text="{Binding Key}" Margin="0,0,10,1"/>
                <TextBlock Text="{Binding Value}" TextWrapping="Wrap" TextAlignment="Right" HorizontalAlignment="Right" />
            </StackPanel>
        </DataTemplate>
    </UserControl.Resources>
    
    <ScrollViewer>
        <ItemsControl ItemTemplate="{StaticResource PropertyTemplate}"
                      ItemsSource="{Binding Path=., Converter={StaticResource ObjectPropertiesConvert}}">                
        </ItemsControl>
    </ScrollViewer>

</UserControl>

With a smidge of C# to create a name value pair collection, given an object's properties
    public class ObjectPropertiesConverter : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                return null;

            return from p in value.GetType().GetProperties()
                   where p.CanRead
                   select new KeyValuePair<string, string>
                   (
                      p.Name,
                      p.GetValue(value, null) != null ? p.GetValue(value, null).ToString() : null
                   );                   
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

Thursday, December 29, 2011

Saturday, December 17, 2011

WebOS? I like it...

So I picked up one of those HP TouchPads from their latest eBay firesale for $150. Mostly intended as a much nerdier replacement for an iPad. Root it, put Android on it, play around with other linux tablet builds, even get Windows 8 on there as soon as that's possible. At a $150 I'm much more comfortable taking the risk of bricking this thing than say the $5-600 pricetag of similar hardware.

So anyway, after a few days of playing around with it and the cyanogenmod 7 build I have to say of the 3 tablet OS's (IOS, WebOS, Android) that I've used WebOS is the most compelling. It's prettier and slicker than IOS and definately better organized and usable than Android. Maybe it's the newness of it for me, but i just plain "like it".

If I had to choose a single OS for every day tablet use (and I do use my tablet every day at work and home) WebOS is the easy first choice for me. If it had word's with friends and stumbleupon I wouldn't even hestiate.

Let's hope that HP's decision to open source it giives it some legs.

Sunday, April 3, 2011

I couldn't agree more

From Linus Torvalds' Linux Kernel style guide:

Now, some people will claim that having 8-character indentations makes
the code move too far to the right, and makes it hard to read on a
80-character terminal screen. The answer to that is that if you need
more than 3 levels of indentation, you're screwed anyway, and should fix
your program.

In short, 8-char indents make things easier to read, and have the added
benefit of warning you when you're nesting your functions too deep.
Heed that warning.


It amazes me how many professional software engineers don't follow this simple convention.

Tuesday, February 1, 2011

Turns out it is the former

As in "We're tidying up in prepartion for the final feature set".

Vail Release Candidate is supposed to be out this week.

I wonder what's going to happen to Vail

I've been running the household media and file storage off of Windows Home Server for over a year now and it works great as a centralized file store/media server.

I've been looking forward to version 2 of WHS, which goes by codename Vail, for quite some time. This is especially true since MS demoed a WP7 app that can access a WHS server from anywhere on the interwebs at CES. But alas Vail has also been through some trails and tribulations since MS announced they are dropping the drive extender technology (basically a software managed JBOD raid that allowed you set set up massive and arbitrary storage pools and easily manage them).

While there are rumors of an impending beta of Vail I am not seeing much out there. Today my one MS Connect product suggestion went from Proposed, to postponed and then to closed. I'm not sure if that means "we're cleaning things up in preparation for defining the final feature set" or "we're cleaning things up because we're closing up shop on this thing".

I sure hope they don't kill WHS. It is nice and easy to install and manage and most of the other competitors out there for a consumer based "server" slash media system are all linuxy; and my brains just to small for remembering how to configure a linux server, especially if I want my XBox to see it.

Sunday, January 16, 2011

GestureBehavior and GestureTrigger

The Silverlight toolkit has a GestureService and GestureListener that allows you to pick up events from gesture input. Oddly enough it doesn't include Xaml types to easily plug those into a page and bind those events to elements and MVVM commands.

Here is an example of using a simple behavior and set of triggers that allow you to do that.

<TextBlock Text="{Binding Welcome}">
    <i:Interaction.Behaviors>
        <li:GestureBehavior/>
    </i:Interaction.Behaviors>
    <i:Interaction.Triggers>
        <li:DoubleTapTrigger>
            <cmd:EventToCommand Command="{Binding DoubleTapCommand}" PassEventArgsToCommand="True"/>
        </li:DoubleTapTrigger>
    </i:Interaction.Triggers>
</TextBlock>
The TextBlock above is bound to a ViewModel that of course has a DoupleTapCommand. In this case a RelayCommand from MVVM Light:
public MainViewModel()
{
    DoubleTapCommand = new RelayCommand<GestureEventArgs>(e =>
    {
        MessageBox.Show("double tap " + e.OriginalSource.ToString());
    });

    DragStartedCommand = new RelayCommand<DragStartedGestureEventArgs>(Drag);
    DragDeltaCommand = new RelayCommand<DragDeltaGestureEventArgs>(Drag);
    DragCompletedCommand = new RelayCommand<DragCompletedGestureEventArgs>(Drag);
}

public RelayCommand<GestureEventArgs> DoubleTapCommand
{
    get;
    private set;
}

And we can implement a quick and dirty drag and drop:
Point _start;
private void Drag(DragStartedGestureEventArgs e)
{
    UIElement ui = e.OriginalSource as UIElement;
    if (ui != null)
    {
        if (!(ui.RenderTransform is TranslateTransform))
            ui.RenderTransform = new TranslateTransform();

        TranslateTransform t = ui.RenderTransform as TranslateTransform;

        _start = new Point();
        _start.X = t.X;
        _start.Y = t.Y;

        e.Handled = true;
    }
}

private void Drag(DragDeltaGestureEventArgs e)
{
    UIElement ui = e.OriginalSource as UIElement;
    if (ui != null)
    {
        TranslateTransform t = ui.RenderTransform as TranslateTransform;

        t.X += e.HorizontalChange;
        t.Y += e.VerticalChange;
        e.Handled = true;
    }
}

private void Drag(DragCompletedGestureEventArgs e)
{
    UIElement ui = e.OriginalSource as UIElement;
    if (ui != null && _start != null)
    {
        if (MessageBox.Show("Press cancel to abort this move.", "Really?", MessageBoxButton.OKCancel) == MessageBoxResult.Cancel)
        {
            TranslateTransform t = ui.RenderTransform as TranslateTransform;

            t.X = _start.X;
            t.Y = _start.Y;
            e.Handled = true;
        }
    }
}

public RelayCommand<DragStartedGestureEventArgs> DragStartedCommand
{
    get;
    private set;
}

public RelayCommand<DragDeltaGestureEventArgs> DragDeltaCommand
{
    get;
    private set;
}

public RelayCommand<DragCompletedGestureEventArgs> DragCompletedCommand
{
    get;
    private set;
}
Code and example is available here.

Monday, January 10, 2011

XNA Here I Come

I'm thinking that an animated aquarium would be a fun little project for the Windows Phone so I've decided to port the WinForms version I did awhile back. After a couple of fruitless hours of trying to wrestle silverlight to do animated images I thought to myself "Wait a minute. This has to be a lot easier in DirectX".

Lo and behold it is because of course frame animation is a big part of game programming. Got the first version whipped up in a just a few hours.

Sunday, December 26, 2010

Extend ViewModelLocator to be a bit more dynamic

I've been using MVVM Light in my Windows Phone development. It's lightweight, has all the base functionality I need and seems pretty solid.

One pattern that MVVM Light uses is a static ViewModelLocator class that holds all of the main/root view models in the application. You declare it as a data source in the app.xaml:
<vm:ViewModelLocator d:isdatasource="True" x:key="Locator"/>

Then in the page Xaml you can do:
DataContext="{Binding Main, Source={StaticResource Locator}}"

This is great when there is basically a 1:1 mapping between the page and the contents of each view model. What it's not so good at is dealing with the situation where you want the same page to bind to multiple view models are structurally equivalent but have different data contents.

Take for instance an RSS viewer (which coincidentally enough I'm working on at the moment). You might have a feed that represents articles form a website and another feed that is discussion posts from the same website. Each feed is further broken down into topic channels. So if we wanted to display each feed as a page, with each topic as a Pivot Item on that page we could distill the page xaml down to:
<controls:Pivot Title="{Binding Name}" 
   ItemsSource="{Binding Topics}" 
   ItemTemplate="{StaticResource RssTopicTemplate}"/>
Now if the ViewModel is statically linked to the page (as above) we need to parametrize the ViewModel as the user navigates from articles to discussions and back. It can be made to work but it violates the Single Responsibility Principle and I just don't like it.

So rather than parameterizing the ViewModel how about we parametrize the page? Let's declare the linkage between ViewModel in page on the ViewModel. We'll declare an attribute that specifies the linkage and allows a parameter to be passed the page in the form of a query string.
[Page("/RssPage.xaml?vm=ArticlesStatic")]
public class ArticlesViewModel : ViewModelBase

...

[Page("/RssPage.xaml?vm=ForumsStatic")]
public class ForumsViewModel : ViewModelBase

In this app the set of navigable items are collections of viewmodels that are displayed in ListBoxes wherein each ViewModel can be selected and navigated to:
public class ContentsViewModel : ViewModelBase
{
   public ObservableCollection<ViewModelBase> Contents 
             { get; private set; }
   public RelayCommand<object> SelectViewModel 
             { get; private set; }

   private void Select(object vm)
   {
      if (vm != null)
      {
         var page = vm.GetType().GetAttribute<PageAttribute>();
         Navigate(page.Page);
      }
   }
}
Then we need a wee bit of code in the page codebehind:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    if (NavigationContext.QueryString.ContainsKey("vm"))
    {
        string key = NavigationContext.QueryString["vm"];
        DataContext = ViewModelLocator.FindViewModel(key);
    }
    base.OnNavigatedTo(e);
}
where FindViewModel is a method added to the ViewModelLocator that returns the correct ViewModel using reflection:
public static object FindViewModel(string key)
{
    var prop = typeof(ViewModelLocator).GetProperty(key, 
              BindingFlags.Public | BindingFlags.Static);

    return prop.GetValue(null, null);
}

I find that moving the linkage between View and ViewModel onto the ViewModel gives us the flexibility to reuse the same UI to display the contents of multiple, structurally equivalent ViewModels, while still maintaining a loose coupling between those two layers.

Friday, December 17, 2010

CPVanity for Windows Phone

I always kind of liked Luc Pattyn's CPVanity app that lets you check out your code project reputation and keep an eye on article ranking.

So here's a WP7 port of it as a small homage. It's up on the marketplace too.

Wednesday, December 15, 2010

Handy Windows Phone 7 resources

Now that I've gotten past the "Hello World" stage of WP7 development here are some code and resources that I've found quite helpful:

Wednesday, December 8, 2010

A helper class to get the current location on a Windows Phone just once

Getting the location on Windows Phone is done via the GeoCoordinateWatcher. The coordinate watcher has a some best practices associated with it one of which is to minimize power consumption. Once you turn this thing on its going to be using the GPS to stream location event back to your app which will hit the battery.

There are some instance where you may not a running notification of the current potion but just want the current position (for instance you may want to initialize the position on a map but not track changes to position).

So this is a small helper class that starts up the coordinate watcher asynchronously, returns the first coordinate found and then shuts it down. One could use TryStart like so:
using (var watcher =  new 
                GeoCoordinateWatcher(GeoPositionAccuracy.Default))
{
    var location = watcher.TryStart
                (false, TimeSpan.FromMilliseconds(1000));
}
but since that will block your UI thread (assuming you call it from the UI) you'd need to wrap it in some asynchronous stuff anyways.
So I use this class:
public class ImmediateLocation : IDisposable
{
    private GeoCoordinateWatcher _watcher;
    private Action<GeoCoordinate> _action;

    public ImmediateLocation(Action<GeoCoordinate> a)
    {
        Debug.Assert(a != null);

        _action = a;
    }

    public void GetLocation()
    {
        if (_watcher == null)
        {
            _watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);
            _watcher.MovementThreshold = 1000;

            _watcher.PositionChanged += new 
                EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>
                (_watcher_PositionChanged);
            _watcher.StatusChanged += new 
                EventHandler<GeoPositionStatusChangedEventArgs>
                (_watcher_StatusChanged);

            _watcher.Start(false);

            if (_watcher.Status == GeoPositionStatus.Disabled
                || _watcher.Permission == GeoPositionPermission.Denied)
                Dispose();
        }
    }

    void _watcher_StatusChanged(object sender, 
        GeoPositionStatusChangedEventArgs e)
    {
        if (e.Status == GeoPositionStatus.Disabled 
            || _watcher.Permission == GeoPositionPermission.Denied)
            Dispose();
    }

    void _watcher_PositionChanged(object sender, 
        GeoPositionChangedEventArgs<GeoCoordinate> e)
    {
        _action(e.Position.Location);
        Dispose();
    }

    public void Dispose()
    {
        if (_watcher != null)
        {
            _watcher.Stop();
            _watcher.PositionChanged -= new 
                EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>
                (_watcher_PositionChanged);
            _watcher.StatusChanged -= new 
                EventHandler<GeoPositionStatusChangedEventArgs>
                (_watcher_StatusChanged);
            _watcher.Dispose();
        }
        _watcher = null;
        _action = null;
    }
}

Then you can just do this:
void InitLocation()
{
     var immediate = new ImmediateLocation(x => location = x);
     immediate.GetLocation();
}

GeoCoordinate location;
It acts like a one time use, fire and forget location setter that cleans itself up when done. It does have Dispose if you want to mange the lifetime more closely.

Sunday, December 5, 2010

New CodeProject article

I just posted an article on codeproject that goes into detail on my experience building a Windows Phone 7 app. Source code included. Check it out.

Microsoft posts a nice improvement to the WP7 progress bar

Showing that your WP7 app is doing some work is as simple as adding a progress bar and setting its IsIndeterminate property to true. This will show the animating dots that glide from left to right in all the WP7 apps.

<ProgressBar IsIndeterminate="{Binding Working}"/>

The problem with the current version of the control is that it animates on the UI thread. So if your UI is doing something as well it can be kind of jerky.

MSDN has a code snippet that moves the animation to the compositor thread. I'd recommend using this approach as it has a noticeable improvement, animating nice and smoothly.

Thursday, December 2, 2010

Got a WP7 app published

There's already a Microsoft last.fm browser/player but since I like last.fm and have some experience with their API, I thought it would be a good WP7 learning tool. Plus it goes a little more in dpeth into the content.

It's published now on the app hub. So that's pretty cool.

Thursday, November 25, 2010

Lesson's learned from my first WP7 App submission

Lesson 1: Don't forget about the Light theme.
I developed the app completely using the Dark theme on my phone and the emulator. Lo and behold switch it to Light and some parts of it were unreadable, especially the ApplicationBar. My first submission was rejected because of this. Other parts just didn't all that good on the Light theme. We'll see how swing #2 goes...

Lesson 2: Don't set the ApplicationBar colors unless you really want those colors on both themes.
You can't DataBind them and they will be switched automatically per Theme by WP7, but not if you have set the colors by hand in your XAML.

Lesson 3: Don't use color icons on the ApplicationBar
Again, they may look great on the dark theme but switch to the Light theme and they will be drawn as black outlines at best, black blobs at worst. Use White on Transparent icons. They look fine on both themes. There are some good ones online. Don't include the outer circle (the app bar adds it) and set the image itself to 24x24.