Simple WP7 Navigation with MVVM Light

by jasonrshaver 31. January 2012 12:42

So, you enjoy the MVVM pattern for your Silverlight or Windows Phone 7 application, but you can't figure out how to perform your navigation from your ViewModel?  Here is a guide that allows you to do this from your ViewModel:

  1. // Option 1
  2. GotoProductCatalogCommand = new RelayCommand(
  3.     () => Navigate("/Views/ProductCatalogPage.xaml"));
  4. // Option 2, now without strings!
  5. GotoProductCatalogCommand = new RelayCommand(
  6.     () => Navigate<ProductCatalogPageViewModel>());

The first option allows you to give a URI to navigate to, just like you would expect, but option two allows your application to navigate based on convention.  Never miss-type a URI again!

All you have to do is add the following to your ViewModel base class or MVVM Light’s ViewModelBase:

  1. public void Navigate<T>()
  2. {
  3.     var UriFragment = String.Format(@"/Views/{0}.xaml"
  4.         , typeof(T).Name.Replace("ViewModel", ""));
  5.     Navigate(UriFragment);
  6. }
  7. public void Navigate(String uriFragment)
  8. {
  9.     var MyFrame = Application.Current.RootVisual as Frame;
  10.     MyFrame.Navigate(new Uri(uriFragment, UriKind.Relative));
  11. }
  12. public void GoBack()
  13. {
  14.     (Application.Current.RootVisual as Frame).GoBack();
  15. }

Notice that my ‘convention’ for Views is to basically take the type name of your ViewModel, remove the string “ViewModel” and look up the file in the “/Views” directory.  Obviously you can move to a more comprehensive convention as your needs require.

Tags: , , , ,

Blog

Statically-Typed RaisePropertyChanged in MVVM Light

by jasonrshaver 30. January 2012 22:39

I am a fan of keeping strings out of my .NET Applications.  In the past I used CSLA and enjoyed the way it loaded properties and change notification without using strings.  Because why work now-a-days is all about creating samples, I use MVVM Light instead. 

For those who don’t understand the what I am talking about, take a look at this example:

// Normal RaiseProperyChanged
RaisePropertyChanged("Products");

// Statically-Typed RaisePropertyChanged
RaisePropertyChanged(() => Products);

To get the same functionality, add the following method to your class (or ViewModel base class):

public void RaisePropertyChanged<T>(Expression<Func<T>> property)
{
    RaisePropertyChanged(property.GetMemberInfo().Name);
}

And if you don’t already have the GetMemberInfo() extension method, Add the following class to your application:

using System.Linq.Expressions;
using System.Reflection;

namespace System.Linq.Expressions
{
    public static class ReflectionExtensionMethods
    {
        public static MemberInfo GetMemberInfo(this Expression expression)
        {
            MemberExpression operand;
            LambdaExpression lambdaExpression = (LambdaExpression)expression;
            if (lambdaExpression.Body as UnaryExpression != null)
            {
                UnaryExpression body = (UnaryExpression)lambdaExpression.Body;
                operand = (MemberExpression)body.Operand;
            }
            else
            {
                operand = (MemberExpression)lambdaExpression.Body;
            }
            return operand.Member;
        }
    }
}

Tags: , , ,

Blog

Sorting a Pivot Viewer 2.0’s Group Items

by jasonrshaver 23. January 2012 13:54

Let’s just say you want to make a PivotViewer for the Periodic Table of Elements.  And lets just say you want it to look something like you remember it in your middle school science book.  You get the data, add a ‘Group’ value to control the columns, but the vertical order is all wrong. 

Here is a quick way to fix this.  I don’t think anyone documented the method for doing this before, so if you have any questions, let me know!

And add the following to your PivotViewer XAML

<pv:PivotViewer x:Name="myPivotViewer" ItemsSource="{Binding}" BorderThickness="0" ViewChanged="myPivotViewer_ViewChanged">

And in code behind, add:

  1. private System.Windows.Controls.Pivot.PivotViewerView _OldView = null;
  2.  
  3. private void myPivotViewer_ViewChanged(object sender, EventArgs e)
  4. {
  5.     if (_OldView != null)
  6.     {
  7.         _OldView.PivotViewerViewUpdating -=
  8.             new EventHandler<PivotViewerViewUpdatingEventArgs>
  9.                 (View_PivotViewerViewUpdating);
  10.     }
  11.     _OldView = myPivotViewer.View;
  12.     _OldView.PivotViewerViewUpdating +=
  13.         new EventHandler<PivotViewerViewUpdatingEventArgs>
  14.             (View_PivotViewerViewUpdating);
  15. }
  16.  
  17. private void View_PivotViewerViewUpdating(object sender
  18.     , PivotViewerViewUpdatingEventArgs e)
  19. {
  20.     e.CollectionView.SortDescriptions.Add(
  21.         new SortDescription("AtomicNumber"
  22.             , ListSortDirection.Ascending));
  23. }

It is very important to make sure you are cleaning up your PivotViewerViewUpdating event reference as shown!

And Ta-Da, you have the following work of art:

clip_image002

Sorry for making such a quick example without any downloadable source, but I figured it was good to get this information out there!

Tags: ,

Blog

PivotViewer V2 Series, Part 4: Tradecards

by jasonrshaver 3. November 2011 09:52

Other articles in the PivotViewer V2 Series:

  • Part 1: Intro
  • Part 2: Creating a Project
  • Part 3: Receiving OData
  • Part 4: Trade Cards
  • Part 5: Pivot Panel
  • Part 6: Links and Interactions
  • Part 7: Pivot Properties
  • Part 8: Multi-facacited Pivot Properties
  • Part 9: Large Data Sets
  • Part 10: Teaching Your Users
  • Part 11: Exposing Your Own Data
  • Part 12: Advanced Sorting
  • Part 13: Advanced Trade Cards
  • Part 14: Working with Excel

This entry builds upon the previous parts.  You can jump right to this point by downloading the following ZIP file, PivotViewerSeries_Part3.zip.

Creating Visuals

So, we have data put into the PivotViewer, but we are missing some exciting visuals.  To create all of the visuals you will see here, we just need to make some changes to MainPage.xaml’s PivotViewer control.

Trade Cards

The visuals each data item in a collection is call a “Trade Card”.  One of the exciting features for PivotViewer 2.0 is that trade cards can be much more dynamic than the previous CXML method of the past.  For example, we can show different trade cards depending on how zoomed in we are.  Or we can show more information as needed. 

Creating a Trade Card

First we need to create a default trade card for our Netflix data.  To do this, we are just going to create a new DataTemplate and attaching it to our PivotViewer control:

  1. <pivot:PivotViewer ItemsSource="{Binding Titles}">
  2.     <pivot:PivotViewer.ItemTemplates>
  3.         <pivot:PivotViewerItemTemplate>
  4.             <Border BorderBrush="Black" BorderThickness="1">
  5.                 <Image Source="{Binding Path=BoxArt.SmallUrl
  6.                             , Converter={StaticResource ImageConverter}
  7.                             , Mode=OneTime}"
  8.                        Width="65" Height="89" />
  9.             </Border>
  10.         </pivot:PivotViewerItemTemplate>
  11.     </pivot:PivotViewer.ItemTemplates>
  12. </pivot:PivotViewer>

And we will also need to add the ImageConverter that will take our image’s URL string and convert it to a Uri object:

  1. using System;
  2. using System.Globalization;
  3. using System.Windows.Data;
  4. using System.Windows.Media;
  5. using System.Windows.Media.Imaging;
  6.  
  7. namespace PivotViewerSeries.Silverlight
  8. {
  9.     public class ImageConverter : IValueConverter
  10.     {
  11.         public object Convert(object value
  12.             , Type targetType
  13.             , object parameter
  14.             , CultureInfo culture)
  15.         {
  16.             ImageSource Output = null;
  17.             if (value != null)
  18.                 Output = new BitmapImage(new Uri(value.ToString()));
  19.             else
  20.                 Output = new BitmapImage();
  21.             return Output;
  22.         }
  23.  
  24.         public object ConvertBack(object value
  25.             , Type targetType
  26.             , object parameter
  27.             , CultureInfo culture)
  28.         {
  29.             throw new NotImplementedException();
  30.         }
  31.     }
  32. }

And finally, reference that converter in our App.xaml:

  1. <Application.Resources>
  2.     <vm:ViewModelLocator x:Key="Locator"
  3.                         d:IsDataSource="True" />
  4.     <this:ImageConverter x:Key="ImageConverter" />
  5. </Application.Resources>

Now when we run our application, we will get the following result.  Be aware, that depending on your connection, it may take a bit for data to load from Netflix and for the images to download.

image

Using Multiple Trade Cards

To use different trade cards at different zoom levels, we can add more PivotViewerItemTemplate objects to the ItemTemplates collection, setting the MaxWidth property each time to tell the object how wide a template can go before showing the next larger one. 

It is important that the aspect ratio for each trade card must be the same, otherwise you will start to see some weird sizing issues. 

First, lets update our small trade card with the MaxWidth:

  1. <!-- Small Trade Card -->
  2. <pivot:PivotViewerItemTemplate MaxWidth="100">
  3.     <Image Source="{Binding Path=BoxArt.SmallUrl
  4.               ,Converter={StaticResource ImageConverter}}"
  5.        Width="65" Height="89" />
  6. </pivot:PivotViewerItemTemplate>

And create a new medium sized trade card that includes the movie title:

  1. <!-- Medium Trade Card -->
  2. <pivot:PivotViewerItemTemplate MaxWidth="500">
  3.     <Border BorderBrush="Black" BorderThickness="0">
  4.         <StackPanel Orientation="Vertical">
  5.             <TextBlock Text="{Binding Name}"
  6.                       Width="176"
  7.                       FontSize="14"
  8.                       FontWeight="Bold"
  9.                       TextWrapping="Wrap"
  10.                       HorizontalAlignment="Center"/>
  11.             <Image Source="{Binding Path=BoxArt.MediumUrl
  12.               ,Converter={StaticResource ImageConverter}}"
  13.        Width="176" Height="240" />
  14.         </StackPanel>
  15.     </Border>
  16. </pivot:PivotViewerItemTemplate>

Which, when zoomed in enough will look like this:

image

And finally, lets create a large trade card that can give us some more information:

  1. <!-- Large Trade Card -->
  2. <pivot:PivotViewerItemTemplate>
  3.                             <Viewbox Width="1200" Height="1636" MinHeight="1636" MinWidth="1200">
  4.     <Grid Width="600" Height="818" >
  5.         <Grid.RowDefinitions>
  6.             <RowDefinition Height="614" />
  7.             <RowDefinition Height="204" />
  8.         </Grid.RowDefinitions>
  9.         <Grid.ColumnDefinitions>
  10.             <ColumnDefinition Width="450" />
  11.             <ColumnDefinition Width="150" />
  12.         </Grid.ColumnDefinitions>
  13.         <Image Grid.Row="0"
  14.               Grid.Column="0"
  15.               Source="{Binding Path=BoxArt.LargeUrl
  16.               ,Converter={StaticResource ImageConverter}}"
  17.               Width="450" Height="614" />
  18.         <StackPanel Grid.Row="0"
  19.                    Grid.Column="1"
  20.                    Orientation="Vertical"
  21.                    Margin="2">
  22.             <TextBlock Text="{Binding Rating
  23.                             , StringFormat='MPAA Rating: {0}'}" />
  24.             <TextBlock Text="{Binding AverageRating
  25.                             , StringFormat='NetFlix Rating: {0} / 5'}" />
  26.             <TextBlock Text="{Binding ReleaseYear
  27.                             , StringFormat='Release Year: {0}'}" />
  28.             <TextBlock Text="{Binding Runtime
  29.                             , StringFormat='Length: {0} seconds'}" />                                    
  30.         </StackPanel>
  31.         <StackPanel Grid.Row="1"
  32.                    Grid.Column="0"
  33.                    Grid.ColumnSpan="2"
  34.                    Orientation="Vertical"
  35.                    Margin="10">
  36.             <TextBlock Text="{Binding Name}"
  37.                       FontSize="36"
  38.                       FontWeight="Bold"
  39.                       TextWrapping="Wrap"/>
  40.             <TextBlock Text="{Binding Synopsis}"
  41.                       FontSize="16"
  42.                       TextWrapping="Wrap"/>
  43.         </StackPanel>
  44.         </Grid>
  45.     </Viewbox>
  46. </pivot:PivotViewerItemTemplate>

Which results in something like the following:

image

If you find your project ‘skipping’ a template, it is likely that your templates are too close in size to each other.  For PivotViewer to take the time to optimize and repaint all the cards, it need to make sure it is worth it, and a 50 or 100 pixel change is viewed as not being worth wild. 

Tags: , ,

Blog

PivotViewer V2 Series, Part 3: Receiving OData

by JasonRShaver 31. October 2011 17:19

Other articles in the PivotViewer V2 Series:

  • Part 1: Intro
  • Part 2: Creating a Project
  • Part 3: Receiving OData
  • Part 4: Tradecards

Connecting To an OData Collection

Lets get some data for PivotViewer to play with.  The easiest protocol for getting data for PivotViewer currently is OData.  This, by far, not the only way to consume data, but PivotViewer is most useful with large data collections and OData is a good way to navigate those feeds (when available). 

A good feed to play with for now is the Netflix OData Catalog API.

Right click on the PivotViewerSeries.Silverlight project and select Add Service Reference:

image

Connecting ViewModel to Data

To get the data from the ‘cloud’ to our PivotViewer, we need to make a stop at the ViewModel first.  Load up ViewModel\MainViewModel.cs and add the following code:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Data.Services.Client;
  5. using System.Linq;
  6. using System.Linq.Expressions;
  7. using GalaSoft.MvvmLight;
  8. using PivotViewerSeries.Silverlight.NetflixOData;
  9.  
  10. namespace PivotViewerSeries.Silverlight.ViewModel
  11. {
  12.     public class MainViewModel : ViewModelBase
  13.     {
  14.         private Uri _DataUri
  15.             = new Uri("http://odata.netflix.com/Catalog/");
  16.  
  17.         private IEnumerable<Title> _Titles;
  18.         public IEnumerable<Title> Titles
  19.         {
  20.             get
  21.             {
  22.                 if (_Titles == null)
  23.                     return new ObservableCollection<Title>();
  24.                 return _Titles;
  25.             }
  26.             set
  27.             {
  28.                 if (_Titles == value)
  29.                     return;
  30.                 _Titles = value;
  31.                 RaisePropertyChanged("Titles");
  32.             }
  33.         }
  34.  
  35.         public MainViewModel()
  36.         {
  37.             var MyContext = new NetflixCatalog(_DataUri);
  38.             var MyData = new DataServiceCollection<Title>(MyContext);
  39.             MyData.LoadCompleted += (o1, e1) =>
  40.             {
  41.                 // This block of code runs when we get results.
  42.  
  43.                 if (e1.Error != null)
  44.                     throw e1.Error;
  45.  
  46.                 if (MyData.Continuation != null)
  47.                 {
  48.                     MyData.LoadNextPartialSetAsync();
  49.                     Titles = MyData;
  50.                 }
  51.                 else
  52.                     Titles = MyData;
  53.             };
  54.             var MyQuery = from c in MyContext.Titles.Take(1000)
  55.                           select c;
  56.             MyData.LoadAsync(MyQuery);
  57.         }
  58.     }
  59. }

This block of code create a collection to hold our list of NetFlix titles.  Then, when our ViewModel is created, we asynchronously load our collection of data via LINQ.

Of special note here is that the DataServiceCollection will automatically page the collection in groups of 500.  When that happens, we get a chance to process the current incomplete set, and call LoadNextPartialSetAsync to get the next set of results. 

Connecting PivotViewer to ViewModel

The last step here is to attached our list of titles to our PivotViewer.  This is much easier to do now with PivotViewer 2.0.  We just have to bind to the ItemsSource property:

  1. <UserControl x:Class="PivotViewerSeries.Silverlight.MainPage"
  2.    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5.    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6.    xmlns:pivot="clr-namespace:System.Windows.Controls.Pivot;assembly=System.Windows.Controls.Pivot"
  7.    mc:Ignorable="d"
  8.    d:DesignHeight="300" d:DesignWidth="400"
  9.    DataContext="{Binding Main, Source={StaticResource Locator}}">
  10.  
  11.     <Grid x:Name="LayoutRoot" Background="White">
  12.         <pivot:PivotViewer ItemsSource="{Binding Titles}">
  13.          
  14.         </pivot:PivotViewer>
  15.     </Grid>
  16. </UserControl>

 

Conclusion

When we run our new application, we should get something like the following:

image

What we are seeing is 1000 NetFlix titles.  Pretty impressive huh?  What, you don’t believe me.  Well, join me on the next step to get some visuals.

Part 4: Tradecards

Tags: , , ,

Blog

PivotViewer V2 Series, Part 2: Creating a Project

by jasonrshaver 31. October 2011 16:35

Other articles in the PivotViewer V2 Series:

  • Part 1: Intro
  • Part 2: Creating a Project
  • Part 3: Receiving oData

Getting Started

The first step to using PivotViewer is creating new Silverlight 5 project.  Open Visual Studio and click File –> New –> Project.  Select the Silverlight Application project from under the Visual C# –> Silverlight node:

image

When the New Silverlight Application dialog appears, select the following options, as well as choosing a name that suits you.  I like to make the change highlighted:

image

Setting Up an MVVM Framework

While we can move forward without the overhead of an MVVM framework, part of what makes PivotViewer 2.0 so exciting is how easy it is to integrate with ViewModels.  Right click on the PivotViewerSeries.Silverlight project and select Add Library Package Reference.  Click Online on the left and type MVVM Light in the search box in the upper right corner.  Then click Install on the MvvmLight package:

image

At this point, some magic happens.  Once it is finished you can close the Add Library Package Reference window.  There are really only two bits of magic here that you need to know about. 

App.xaml Locator Resource

The first bit of magic is to know that the NuGet package changed your App.xaml to look something like this:

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            x:Class="PivotViewerSeries.Silverlight.App"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:vm="clr-namespace:PivotViewerSeries.Silverlight.ViewModel"
            mc:Ignorable="d">
  <Application.Resources>
    <vm:ViewModelLocator x:Key="Locator"
                        d:IsDataSource="True" />
  </Application.Resources>
</Application>

ViewModelLocator.cs

The second bit of magic is that a ViewModelLocator.cs file gets created in the newly created ViewModel folder.  This Locator object gets created when the application loads up and will be used by our Silverlight controls to load our ViewModels.  For each ViewModel, we will be adding a property pointing to it. 

Connecting MainPage.xaml To MainViewModel.cs

If you open MainPage.xaml and add the bolded DataContext to the UserControl, you have finished setting up our MainPage to use MainViewModel.  Simple huh?

<UserControl x:Class="PivotViewerSeries.Silverlight.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"
   mc:Ignorable="d"
   d:DesignHeight="300" d:DesignWidth="400"
  DataContext="{Binding Main, Source={StaticResource Locator}}">

    <Grid x:Name="LayoutRoot" Background="White">

    </Grid>
</UserControl>

Adding Our PivotViewer Control

The last step to creating a PivotViewer project is to add the pivot viewer.  First we need to add a reference to the Pivot assembly.  Right click on your PivotViewerSeries.Silverlight project and select Add Reference and select the System.Windows.Controls.Pivot assembly:

image

Add the following to the XAML namespaces in MainPage.xaml:

xmlns:pivot="clr-namespace:System.Windows.Controls.Pivot;assembly=System.Windows.Controls.Pivot"

And finally, inside the LayoutRoot Grid control, add the PivotViewer control:

<pivot:PivotViewer>
   
</pivot:PivotViewer>

Now, If you run your application, you should see an empty PivotViewer:

image

Conclusion

You should now have a Silverlight Project complete with MVVM framework and working PivotViewer.  Attached is a ZIP file containing a copy of my project up to this point.

Up next, Part 3: Receiving oData

Tags: , , , , ,

Blog

PivotViewer V2 Series, Part 1: Intro

by JasonRShaver 30. October 2011 15:51

As part of being a Program Manager at Microsoft, I am responsible for talk with and helping customers for a few technologies.  Of following set:

  • Silverlight Toolkit
  • Silverlight Data & Data-Binding
  • Silverlight Parser
  • Silverlight Line of Business
  • PivotViewer (v1 and v2)

I find that 90% of my customer emails want information/help/advice on PivotViewer.  While using the new version is really simple, I find there is still very little good documentation for how to use it and some of the best practices around it.  To correct that, I am kicking off a new series of blog posts all about using PivotViewer. 

Why am I doing this now?  Well I am headed back to Chicago to pack-up my house and move my ‘stuff’ to Redmond and while I am sitting there watching my life get put into boxes and loaded onto a truck, I figured this would be a good time to complete some work on this subject.  Also, I can then just point customers at work to my blog instead of having to type up the same thing 10 times a week =)

What You Will Need

Install all of the above (in the order shown is a good idea) and off we go:

PivotViewer V2 Series, Part 2: Creating a Project

Tags: , ,

Blog

Guide For Building a New Line of Business Application

by JasonRShaver 18. October 2011 23:53

Make note that I define a line of business (LOB) application as:

An application needing centrally stored/processed data; using its own networking contracts, where requirements change rapidly.

This given as a counterpoint to some common consumer-focused applications such as:

  • Angry Birds, games generally don't have changing requirements, only new levels
  • Weather Applications, they do not store and/or process data, only pull data from simple web APIs
  • Facebook applications, they process data, but don't have their own data contracts

So, with that in mind, I plan to cover all the points a normal LOB developer would need to cover, but I will use tricks, such as attached databases, that will speed development.  In addition, I will not be covering items that are just good practice, such as using source control, even for yourself. 

I am also not doing this from a clean machine, so if I am missing anything, such as a download link, contact me.

Finally, I am focusing on using ASP.NET MVC 3 and Windows Phone 7.5 (Mango).  In the future I may make additions covering:

  • Integrating the phone’s navigation into MVVM Light
  • Adding and sharing code with Silverlight 5
  • Adding and sharing code with ASP.NET MVC 3
  • More complex data relationships (foreign keys, many-to-many, blobs)
  • Porting the ASP.NET and database site over to Azure
  • Publishing your application on the App Store
  • Integration with my Offline (Occasionally Disconnected) Application demo
  • Better “Design-Time Data”

Adding the Web Application

Ok, let’s start with the basics, open Visual Studio 2010 and create a new ASP.NET MVC 3 Web Application, I think you may need to download and install this package.

image
and on the next screen, select “Internet Application”.  I personally don’t create a unit test project at this point, I think it is better to just build it yourself at a later point.

image

Creating your Database

Now, let's get a database into the mix.  In your Solution Explorer (if you don’t see it, the hotkey is Ctrl + W, S), right click on App_Data and click Add and select New Item… and select SQL Server Database and give it a name like so:

image

Now, in the Solution Explorer, expand App_Data and double click on LobData.mdf to open it in the Server Explorer.

Now, right click on the Tables folder and select Add New Table:

image

Now, I am only planning on touching on the core point here, but you will ultimately want to create your schema as needed.  Here is the one I am going to roll with for now:

image

But, it is a good idea to set a Primary Key, and Row GUID Column.  To set the primary key, right click on your CustomerGuid column and select Set Primary Key.  Now in the Properties window (F4), make sure you don’t have any columns selected and change the Row GUID Column to CustomerGuid:

image

Click Save, give the table a name, such as “Customer” and you should be done with the database for now.

Creating your Entities

Now I personally love using a more ‘enterprise’ framework, such as CSLA, for the sake of time, we'll just stick with Entity Framework.  So, right click on your project and select Add and New Item… and choose the following:

image

and make sure to give it a name, such as LobModel.edmx in my case.  Then choose from the following sets of options:

image
image
image

And you should be dropped right into the edmx Model Editor:

image

And that’s all you need for that step, but first, let's add some sample data.  I like to plan my sample data to work two ways: Create it when I need it, or setup new sample data every time.  To make this happen I like to add an AddSampleData method to my Global.asax.cs; let’s do that now:

  1. protected void Application_Start()
  2. {
  3.     AreaRegistration.RegisterAllAreas();
  4.  
  5.     RegisterGlobalFilters(GlobalFilters.Filters);
  6.     RegisterRoutes(RouteTable.Routes);
  7.  
  8.     AddSampleData();  // Add this
  9. }
  10.  
  11. // Create this
  12. private void AddSampleData()
  13. {
  14.     var MyContext = new LobDataEntities();
  15.     if (MyContext.Customers.Count() != 0)
  16.         return;
  17.  
  18.     MyContext.AddToCustomers(new Customer()
  19.     {
  20.         CustomerGuid = Guid.NewGuid(),
  21.         FirstName = "First",
  22.         LastName = "Customer",
  23.         Level = 1,
  24.         Created = DateTime.Now,
  25.         LastUpdated = DateTime.Now,
  26.     });
  27.     MyContext.AddToCustomers(new Customer()
  28.     {
  29.         CustomerGuid = Guid.NewGuid(),
  30.         FirstName = "Second",
  31.         LastName = "Guy",
  32.         Level = 2,
  33.         Created = DateTime.Now,
  34.         LastUpdated = DateTime.Now,
  35.     });
  36.     MyContext.AddToCustomers(new Customer()
  37.     {
  38.         CustomerGuid = Guid.NewGuid(),
  39.         FirstName = "That",
  40.         LastName = "Other One",
  41.         Level = 2,
  42.         Created = DateTime.Now,
  43.         LastUpdated = DateTime.Now,
  44.     });
  45.     MyContext.SaveChanges();
  46. }

Now, if you want to have clean data every time, just remove the if statement.

Adding Your Windows Phone 7.5 (Mango) Project

First, I think you need to install this package.  Once you have that (and restarted Visual Studio), right click on your solution and select Add and select New Project… and select the following:

image

And select Windows Phone 7.1 from the New Windows Phone Application dialog.  Now, if I have learned anything from being a Program Manager at Microsoft, it is that when you create new applications all the time (I am up to “SilverlightApplication52” on this computer), learn to LOVE NuGet.  Let me show you how…  Come on, don’t fight it.

Right click on your Silverlight project and select Manage NuGet Packages… and enter MVVM Light into the “Search Online” box in the upper right hand corner and click the Install button on the first item that shows up:

image

Now, there are a lot of MVVM frameworks, and trust me, I have tried them all (or at least it feels like it).  I can say I am impressed with MVVM Light, BxF, and Caliburn Micro, but for the purpose of creating an application in 5 minutes or less and avoiding as much magic as possible, MVVM Light by Laurent Bugnion is awesome.

While we are at it, let’s get the Silverlight Toolkit for Windows Phone.  Search for “windows phone toolkit” and click Install:

image

Building the Solution

Right click on your solution and select Build Solution. Yup, not joking, this is a step.  If you skip this step, Entity Framework will not generate the code that we will need for the next step.  Please don’t skip it. 

Connecting Your Client And Server

To get the data from the web server to the phone and back again, we are going to use oData.

Getting the Server Ready

This might be a good time to talk about your options, but if you want to do this fast and easy, you really don’t have any.  The first step is to wrap our entities as a DataService<T>. 

First, add a reference to System.Data.Services, System.Data.Services.Client and System.ServiceModel DLLs that should be in your GAC.  Then create a new folder in the root of you web project called Services and create a new WCF Data Service like so:

image

And replace the contents of the LobEntities.svc.cs file with the following:

  1. using System.Data.Services;
  2. using System.Data.Services.Common;
  3. using System.ServiceModel;
  4.  
  5. namespace LobApplication.Services
  6. {
  7.     [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
  8.     public class LobEntities : DataService< LobApplication.LobDataEntities >
  9.     {
  10.         public static void InitializeService(DataServiceConfiguration config)
  11.         {
  12.             config.SetEntitySetAccessRule("*", EntitySetRights.All);
  13.             config.DataServiceBehavior.MaxProtocolVersion =
  14.                 DataServiceProtocolVersion.V2;
  15.         }
  16.     }
  17. }

and if you F5 your web application and go to the following address:

http://localhost:[WhateverYourPortIsGoesHere]/Services/LobEntities.svc/

you should see the following:

image

Ok, I know, not that impressive, but we will get there. 

Silverlight (or WP7) and oData, Friends Forever!

If you want to get data back and forth in a modern application, I can’t see myself going with anything other than oData for all but the most hard-core enterprise applications.  It seems to be supported on everything, pretty much everywhere, and works great with Azure. 

Hell, did you know that SQL Server 2008 R2 can host a database as oData without any other tools?  Spin up SQL Server Management Studio, right click on a database, select Tasks and Register as Data-tier Application… and you will get a nice wizard walking you though the process.  More data can be found here.

image

Ok, back to the walkthrough:

Go to your Windows Phone project, right click on Service References and select Add Service Reference.

image

Click Discover and it should automatically find your service.  Give it a name and click OK.

You're done, the data is there. 

Don’t trust me?  Do we need to prove it to you.  Ok, fine, but I want to let you know that that hurts.

Making Your First ViewModel

On the Windows Phone project, the MVVM Light NuGet package creates a ViewModel\MainViewModel.cs class for you.  Let's go there, it looks something like this (with the comments removed).

  1. using GalaSoft.MvvmLight;
  2.  
  3. namespace LobApplication.Silverlight.ViewModel
  4. {
  5.     public class MainViewModel : ViewModelBase
  6.     {
  7.         public MainViewModel()
  8.         {
  9.             ////if (IsInDesignMode)
  10.             ////{
  11.             ////    // Code runs in Blend --> create design time data.
  12.             ////}
  13.             ////else
  14.             ////{
  15.             ////    // Code runs "for real"
  16.             ////}
  17.         }
  18.     }
  19. }

So, let’s get our data into the mix. 

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Data.Services.Client;
  5. using System.Linq;
  6. using GalaSoft.MvvmLight;
  7. using LobApplication.Silverlight.LobEntitiesService;
  8.  
  9. namespace LobApplication.Silverlight.ViewModel
  10. {
  11.     public class MainViewModel : ViewModelBase
  12.     {
  13.         private Uri _DataUri = new Uri("http://localhost:35772/Services/LobEntities.svc/");
  14.  
  15.         private IEnumerable<Customer> _Customers;
  16.         public IEnumerable<Customer> Customers
  17.         {
  18.             get
  19.             {
  20.                 if (_Customers == null)
  21.                     return new ObservableCollection<Customer>();
  22.                 return _Customers;
  23.             }
  24.             set
  25.             {
  26.                 if (_Customers == value)
  27.                     return;
  28.                 _Customers = value;
  29.                 RaisePropertyChanged("Customers");
  30.             }
  31.         }
  32.  
  33.         public MainViewModel()
  34.         {
  35.             if (IsInDesignMode)
  36.             {
  37.                 // Code runs in Blend --> create design time data.
  38.             }
  39.             else
  40.             {
  41.                 var MyContext = new LobDataEntities(_DataUri);
  42.                 var MyData = new DataServiceCollection<Customer>(MyContext);
  43.                 MyData.LoadCompleted += (o1, e1) =>
  44.                 {
  45.                     // This block of code runs when we get results.
  46.  
  47.                     if (e1.Error != null)
  48.                         throw e1.Error;
  49.  
  50.                     if (MyData.Continuation != null)
  51.                         MyData.LoadNextPartialSetAsync();
  52.                     else
  53.                         Customers = MyData;
  54.                 };
  55.                 var MyQuery = from c in MyContext.Customers
  56.                               select c;
  57.                 MyData.LoadAsync(MyQuery);
  58.             }
  59.         }
  60.     }
  61. }

Connecting Your ViewModel to XAML

In our MainPage.xaml, we connect our ViewModel to our page’s DataContext, using MVVM Light’s ViewModelLocator to help make this easy.  To do this, put the following attribute into your PhoneApplicationPage element, and then just bind a list box to your ViewModel’s Customer property. 

  1. <phone:PhoneApplicationPage
  2.    x:Class="LobApplication.Silverlight.MainPage"
  3.    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  4.    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  5.    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
  6.    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
  7.    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  8.    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  9.    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
  10.    FontFamily="{StaticResource PhoneFontFamilyNormal}"
  11.    FontSize="{StaticResource PhoneFontSizeNormal}"
  12.    Foreground="{StaticResource PhoneForegroundBrush}"
  13.    SupportedOrientations="Portrait" Orientation="Portrait"
  14.    DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
  15.    shell:SystemTray.IsVisible="True">
  16.    
  17.     <Grid x:Name="LayoutRoot"
  18.          Background="Transparent">
  19.         <Grid.RowDefinitions>
  20.             <RowDefinition Height="Auto"/>
  21.             <RowDefinition Height="*"/>
  22.         </Grid.RowDefinitions>
  23.  
  24.         <StackPanel x:Name="TitlePanel"
  25.                    Grid.Row="0"
  26.                    Margin="12,17,0,28">
  27.             <TextBlock x:Name="ApplicationTitle"
  28.                       Text="LOB Application"
  29.                       Style="{StaticResource PhoneTextNormalStyle}"/>
  30.             <TextBlock x:Name="PageTitle"
  31.                       Text="Customer View" Margin="9,-7,0,0"
  32.                       Style="{StaticResource PhoneTextTitle1Style}"/>    
  33.         </StackPanel>
  34.  
  35.         <ListBox Grid.Row="1"
  36.                 ItemsSource="{Binding Customers}">
  37.             <ListBox.ItemTemplate>
  38.                 <DataTemplate>
  39.                     <Grid Margin="40 4 0 0">
  40.                         <Grid.RowDefinitions>
  41.                             <RowDefinition Height="Auto"/>
  42.                             <RowDefinition Height="Auto"/>
  43.                         </Grid.RowDefinitions>
  44.                         <Grid.ColumnDefinitions>
  45.                             <ColumnDefinition Width="60px" />
  46.                             <ColumnDefinition Width="*" />
  47.                         </Grid.ColumnDefinitions>
  48.                        
  49.                         <TextBlock Grid.RowSpan="2" Text="{Binding Level}"
  50.                                   Style="{StaticResource PhoneTextTitle1Style}"/>
  51.                         <TextBlock Grid.Column="1"
  52.                                   Text="{Binding FirstName}"
  53.                                   Style="{StaticResource PhoneTextNormalStyle}"/>
  54.                         <TextBlock Grid.Row="1" Grid.Column="1"
  55.                                   Text="{Binding LastName}"
  56.                                   Style="{StaticResource PhoneTextNormalStyle}"/>
  57.                     </Grid>
  58.                 </DataTemplate>
  59.             </ListBox.ItemTemplate>
  60.         </ListBox>
  61.     </Grid>
  62.  
  63. </phone:PhoneApplicationPage>

Finally, Results��

And when you run your Silverlight application, you should get results like this:

image

And that, I think a good place to stop for now.  If you followed the steps, you have a great framework that combines ASP.NET MVC 3, WCF Data Services (oData), Windows Phone Mango, MVVM, and SQL Server Express. 

That’s not a bad place to start your Silverlight journey. 

Tags: , , , , , ,

Blog

WP7 Client Certificates Part 2 (Client Certs on the Browser)

by jasonrshaver 28. September 2011 15:55

This post is part of a series on using client certificates in Windows Phone 7. I expect there to be 3 parts involved:

  1. Setting Up IIS Express
  2. Client Certificates on the Browser
  3. Client Certificates on the Emulator
  4. Client Certificates on the Phone

Setting Up IIS Express to Accept Client Certificates

First, lets tell IIS Express that we want to accept client certificates.  To do this, lets open up the IIS Express application host configuration file located at:

C:\Users\{Your User Name}\Documents\IISExpress\config\applicationhost.config

and as always, make a backup before modifying this file!  Make a notice of your site configuration located around line 161:

<site name="WebSecurity" id="2">
    <application path="/" applicationPool="Clr4IntegratedAppPool">
        <virtualDirectory path="/" physicalPath="D:\Scratchpad\WebSecurity\WebSecurity" />
    </application>
    <bindings>
        <binding protocol="http" bindingInformation="*:5382:localhost" />
        <binding protocol="https" bindingInformation="*:44300:localhost" />
    </bindings>
</site>

Go to about line 330 and change the enabled attribute of the iisClientCertificateMappingAuthentication element to enabled:

<iisClientCertificateMappingAuthentication enabled="false">

And if you go to around line 314, replace the access element to the following block:

  <!-- If the user is using SSL and has a client certificate, use it -->
  <access sslFlags="SslNegotiateCert" />

  <!--Require SSL *AND* use a client certificate if there is one -->
  <!--<access sslFlags="Ssl, SslNegotiateCert" />-->

  <!--Require SSL *AND* require a client certificate -->
  <!--<access sslFlags="Ssl, SslRequireCert" />-->

You will see that there are 3 options in the above block.  For the sake of debugging, lets leave the first option, SslNegotiateCert, as the uncommented one.

Save the file, run your web application and you will now find that it asks you to select a client certificate.  In my case, working at Microsoft, I have lots:

image

Create a Client Certificate and Trust Chain

But, I don’t want to use a certificate from work, I want to create my own certificate.  To do that, we really need to create two certificates, a ‘localhost’ certificate to act as our client certificate, and a root certificate that we can place in our trusted root store. 

To do this, click Start and type ‘cmd’, right click on the ‘cmd.exe’ and select Run as Administrator.  Type “cd “\program files (x86)\Microsoft SDKs\Windows\v7.0A\bin” or wherever you may have a copy of makecert.exe installed.

First, lets create a new root certificate:

makecert -n "CN=localhost" -r -sv localhostCA.pvk localhostCA.cer

When you do this, you will be asked for a password to protect the private key.  You can choose none if you wish.  Now we need to use our new localhostCA certificate to issue a new client certificate:

makecert -pe -ss My -sr CurrentUser -a sha1 -sky exchange -n CN=localhost -sk SignedByLocalHostCA -ic localhostCA.cer -iv localhostCA.pvk

Now, before we can use that certificate, we need to ‘trust’ our LocalhostCA certificate.  Type the following into our command prompt:

start LocalhostCA.cer

and click Install Certificate:

image

And select “Place all certificates in the following store” and select Browse…

image

Click the Show physical stores checkbox and select Trusted Root Certification Authorities and Local Computer.

image

And than OK, Next, and Finish.  You should be greeted by a friendly “The import was successful.” dialog.

Now, lets go back to our web application created in Part 1 and hit F5.

image

Boom, now select the “localhost” certificate and you should be good to go.

Using the Client Certificate

So, now that we have a client certificate, how do we use it?  In our web project, go to Views\Home\Index.cshtml and add the following:

@{
    ViewBag.Title = "Home Page";
}

@if (Request.ClientCertificate.IsPresent == false)
{
<p>
    Client Certificate is not present.
</p>
}
else {
    <p>
    Client Certificate is found.<br /><br />

    User: <span>@User.Identity.Name</span> <br /><br />

    Certificate Details: <br />
    Issuer: <span>@Request.ClientCertificate["ISSUER"]</span><br />
    Subject: <span>@Request.ClientCertificate["SUBJECT"]</span><br />
    Serial Number: <span>@Request.ClientCertificate["SERIALNUMBER"]</span><br />
    Valid From: <span>@Request.ClientCertificate["VALIDFROM"]</span><br />
    Valid Till: <span>@Request.ClientCertificate["VALIDUNTIL"]</span><br />
    </p>        
}

F5 your application, select your client certificate and you should see something like the below:

image

Congratulations, in the next article, we will connect all this with a Windows Phone 7 project.

Tags: , , , ,

Blog

WP7 Client Certificates Part 1 (Setting Up IIS Express)

by JasonRShaver 28. September 2011 13:39

This post is part of a series on using client certificates in Windows Phone 7.  I expect there to be 3 parts involved:

  1. Setting Up IIS Express
  2. Client Certificates on the Browser
  3. Client Certificates on the Emulator
  4. Client Certificates on the Phone

Setting Up IIS Express

Create a new ASP.NET MVC 3 Web Application project

image

And select Internet Application with the default settings

image

Now to work with SSL, we need to use either IIS or IIS Express, and since I seem to make new applications every 15 minutes, I figure this is a good chance to get familiar with IIS Express.  The first step is to install IIS Express via the Web Platform Installer by following this link.  Once you are done clicking on a few accept/allow dialogs and clicking on the final Install button, wait for the install to finish and then restart Visual Studio 2010.

Right click on your web project and select “Use IIS Express”

image

and click Yes on the following dialog:

image

and note the address given at the next dialog:

image

Now to enable SSL, click on your project, pull up the Properties panel (F4) and set SSL Enabled to True.

image

And again, note the SSL URL which should be something like https://localhost:44300.  Lets set that as the default URL for our debugging.  Right click on the web project and select properties.  Go to the Web tab and update the Project Url under Use Local IIS Web server.

image 

Now, you should be able to F5 your project.  A security validation error will come up, if you click on the scary looking “Continue to this website (not recommended)”, you should see your website come up normally.

imageimage

Trusting Your Self Signed Certificate

So, now we are in the realm of security and certificates.  Lets start by telling our development machine to trust the SSL self-signed certificate that gets automatically created by IIS Express.  Click on Start, type ‘mmc’ and run the mmc.exe application.  Click File, and select Add/Remove Snap-In….  Double-click on Certificates and select Computer Account when the Certificates snap-in dialog pops up and click next.  On the next dialog, Local Computer should be selected and click Finish.

image

The resulting screen should look like this:

image

and after selecting OK, expand the Certificates (Local Computer) node on the left, and the Certificates node underneath that.  Find the localhost certificate issued by localhost.  Drag that certificate to the Trusted Root Certification Authorities node.  The result should look like this:

image

Now, lets go back to our web application and F5 our application again.  If everything went well, the web page should come right up without any errors and the address bar should no longer be a scary red:

image

Quick recap, where are we right now.  We have a web application, using SSL via IIS Express with a trusted self-signed certificate.  Let’s take this the next step, using self-signed client certificates.

Tags: , , , , ,

Blog

About the author

I am a software developer working for Microsoft in Redmond, WA.  In addition, my wife and I own TTXOnline, what is likely the 3rd largest table tennis store in the US.

Month List

Page List