Skip to content
Archive of posts filed under the Windows Phone 7 category.

VS Live Orlando 2011

As I mentioned before, I presented at VS Live conference in Orlando, FL Thursday, 12/08/2011. I presented the following two talks

Working with Data on Windows Phone 7
I will talk about various approaches to work with data on Windows Phone 7. I will cover all major concepts, such as local storage, OData/WCF Data Services and custom WCF services. I will demonstrate how to retrieve data and save changes locally or to a remove web server. I will build demos for all technologies step-by-step.

You will learn:
• About options to persist the data on Windows Phone 7
• About pros and cons of each technologies
• Knowledge to build a Windows Phone application that publishes and/or consumes data

You can download the materials for this presentation here.

Using Code First (Code Only) Approach with Entity Framework
Session will include high level overview of Entity Framework and how various approaches to use it fit into application development lifecycle. Then I will build POCO classes that entity framework can use to create database as well as perform CRUD operations against the database. Various attributes that are included out of the box will be covered. This will include columns constraints, relationships, etc. I will show you how ASP.ENT MVC 3 can utilize entity framework code first metadata to build automatic validation of user input.
You will learn:
• How to build data access layer with Entity Framework Code First
• About validation approaches using POCO classes
• Fluent API and attribute based configuration option

You can download the materials for this presentation here.  I spent a lot of time answering questions, which I really enjoy, so I ran a bit short on time covering MVC.  On a positive note, you can still see the project in the download zip file.

Feel free to ask any questions related to the presentations in the comments or email me directly.  You can find my email address on Contact Me page on this blog.

Post to Twitter

VS Live Orlando

I will be speaking at VS Live conference in Orlando, FL on 12/08/2011. I will be presenting the following two talks.

Working with Data on Windows Phone 7
I will talk about various approaches to work with data on Windows Phone 7. I will cover all major concepts, such as local storage, OData/WCF Data Services and custom WCF services. I will demonstrate how to retrieve data and save changes locally or to a remove web server. I will build demos for all technologies step-by-step.

You will learn:
• About options to persist the data on Windows Phone 7
• About pros and cons of each technologies
• Knowledge to build a Windows Phone application that publishes and/or consumes data

You can download the materials for this presentation here.

Using Code First (Code Only) Approach with Entity Framework
Session will include high level overview of Entity Framework and how various approaches to use it fit into application development lifecycle. Then I will build POCO classes that entity framework can use to create database as well as perform CRUD operations against the database. Various attributes that are included out of the box will be covered. This will include columns constraints, relationships, etc. I will show you how ASP.ENT MVC 3 can utilize entity framework code first metadata to build automatic validation of user input.

You will learn:
• How to build data access layer with Entity Framework Code First
• About validation approaches using POCO classes
• Fluent API and attribute based configuration option

I hope to see you there. 

Thanks.

Post to Twitter

VS Live Redmond 2011

As I mentioned before, I presented at VS Live conference in Redmond, WA yesterday, 10/20/2011.  I presented the following two talks

Working with Data on Windows Phone 7
I will talk about various approaches to work with data on Windows Phone 7.  I will cover all major concepts, such as local storage, OData/WCF Data Services and custom WCF services.  I will demonstrate how to retrieve data and save changes locally or to a remove web server.  I will build demos for all technologies step-by-step.

You will learn:
• About options to persist the data on Windows Phone 7
• About pros and cons of each technologies
• Knowledge to build a Windows Phone application that publishes and/or consumes data

You can download the materials for this presentation here.

Using Code First (Code Only) Approach with Entity Framework
Session will include high level overview of Entity Framework and how various approaches to use it fit into application development lifecycle.  Then I will build POCO classes that entity framework can use to create database as well as perform CRUD operations against the database.  Various attributes that are included out of the box will be covered.  This will include columns constraints, relationships, etc. I will show you how ASP.ENT MVC 3 can utilize entity framework code first metadata to build automatic validation of user input.
 
You will learn:
• How to build data access layer with Entity Framework Code First
• About validation approaches using POCO classes
• Fluent API and attribute based configuration option

You can download the materials for this presentation here.

Post to Twitter

Update for WP7 Database

I have had a small number of requests to enhance the functionality of my Windows Phone 7 database project on CodePlex.  In light of Mango release for WP 7 that will contain SQL CE database, I think that my project will likely be used less in just a few months.  The reason being is that once the users update, the reason to use Isolated storage to persist data becomes less appealing.  I am not knocking on my own project, I am just recognizing the reality.  Having said that, the database will likely still be in use for a while, since we have to wait for the actual phone users to update the version, which cannot be done via 3G, you have to use Zune to update.  Because of that, I think, I decided to implement the most request feature, specifically named tables.  In other words, right now you can create a table in my database and give it a type of data to store, such as :

db.CreateTable<Person>();

 

What named tables allow you to do, is horizontally partition your data by allowing multi0ple tables to store the same type, such as:

string name2 = "p2";
Database db = Database.CreateDatabase("test"
);
db.CreateTable<
Person
>(name1);

 

So, the syntax pretty much remains the same, so anywhere you used to refer to db.Table<T>, you can now also use db.Table<T>(tableName).  This includes all functions, such as adding of rows and querying.

db.Table<Person>(name1).Add(NewRandomPerson());

 

Nothing else changes.  One thing to notice, that this is pretty deep change that required me to touch a lot of code and test legacy data to ensure it opens properly.  As always, I did my due diligence, as you can gather from the tiny number of reported issues in over a year of usage.  Nevertheless, I encourage everyone to thoroughly test your applications.  You can open up my test project and see how I tested legacy data by looking at the method NamedTablesLegacyTest in my test page in test project.  As a result, I am going to publish this release under alpha version until I get some feedback that is sufficient enough to warrant beta status.

I made another small change, making DoesTableExist method public.

Enjoy.

Thank you.

Post to Twitter

More Changes to Calendar Control for WP 7

In the spirit of further improving my calendar control for Windows Phone 7, I added ability to show week number in the first column of the calendar control.

image

As you can see, the very first column can show week number,.  If course, I cannot break existing functionality, so the feature is disabled by default.  You can enable it by setting appropriate property on calendar control, called WeekNumberDisplay.  It has three options:


namespace WPControls
{
 
   
/// <summary>

   
/// Option of how to display week numbers in the calendar
   
/// </summary>
   
public enum WeekNumberDisplayOption
    {
       
/// <summary>
       
/// Do not show week number
       
/// </summary>
        None = 0,
       
/// <summary>
       
/// Show week number starting with start of the year
       
/// </summary>
        WeekOfYear = 1,
       
/// <summary>
       
/// Show week number starting with start of month
       
/// </summary>

        WeekOfMonth = 2
    }
}

 

So, you have options to show week of the year, week of the month or none.  Week of the month is simply number that starts with 1.  As far as week of the year goes, I am using built in functionality to properly determine this using localization rules as follows.

var systemCalendar = System.Threading.Thread.CurrentThread.CurrentCulture.Calendar;
weekNumber = systemCalendar.GetWeekOfYear(
  item.ItemDate,
  System.Threading.
Thread
.CurrentThread.CurrentCulture.DateTimeFormat.CalendarWeekRule,
  System.Threading.
Thread
.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek);

 

You can use this code any time you need to determine week number.

You can visit the home page for calendar control to download the latest source code.

http://wpcontrols.codeplex.com/

Thank you and keep the suggestions coming.

Post to Twitter

Update to Calendar Control for Windows Phone 7

Today due to numerous requests (technically one request from one person Smile), I updated my CodePlex project for calendar control for Windows Phone 7 – http://wpcontrols.codeplex.com/.

I added gesture support to the project.  You can now swipe (flick) from side to side to increment or decrement month, and swipe top to bottom and back to increment or decrement year.

I thought it was a very good enhancement idea that feels very natural to me to support on Windows phone.  I used XNA libraries to enable this support, and it only required a few lines of code.  To enable support you will need to set property on the calendar control – EnableGestures – to true.

Please let me know if you have any feedback.

Thanks.

Post to Twitter

Consuming WCF REST Service from WP 7

In this post I will explore a possibility of talking to a WCF REST Service from a Windows Phone 7 device.  This should complete my posts related to consuming and working with data on Windows Phone 7.

I am going to start with creating a WCF REST Service.  First of all, I am going to create data using Entity Framework Code First.  I am going to re-use classes with my previous posts.  I am going to define a handful : Attendee, Session and Session Category.  Here is what Attendee class looks like as it will be the class I will use in my services.

using System.Collections.Generic;
using
System.ComponentModel.DataAnnotations;
 

namespace
VSLiveData.EF
{
   
public class Attendee

    {
        [
Key]
       
public int AttendeeID { get; set
; }
 
        [
StringLength(50), Required
]
       
public string FirstName { get; set
; }
 
        [
StringLength(50), Required
]
       
public string LastName { get; set
; }
 
        [
StringLength(int
.MaxValue)]
       
public string Notes { get; set
; }
 
       
public virtual ICollection<Session> Sessions { get; set
; }
    }
}

 

Nest step is to define a service.  .NET 4 comes with a template for RESTfull WCF Service, and I am going to use it to get a head start on my code.  I am going to right click on my solution, and in Add New Item dialog I will select WCF REST Service Applications.

image

In next step I will rename and update created service.  I am going to rename it to JSONDataService.  I am going to start with a method that get list of attendees sorted by last name:

 

using System.Collections.Generic;
using
System.Linq;
using
System.ServiceModel;
using
System.ServiceModel.Activation;
using
System.ServiceModel.Web;
using
VSLiveData.EF;
 

namespace
WcfRestService
{
    [
ServiceContract
]
    [
AspNetCompatibilityRequirements
(
        RequirementsMode =
AspNetCompatibilityRequirementsMode
.Allowed)]
    [
ServiceBehavior(InstanceContextMode = InstanceContextMode
.PerCall)]
   
public class JSONDataService

    {
 
        [
WebGet(UriTemplate = "/Attendee/List", ResponseFormat = WebMessageFormat.Json)]
       
public List<Attendee
> GetList()
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Configuration.LazyLoadingEnabled =
false
;
                context.Configuration.ProxyCreationEnabled =
false
;
               
return
context.Attendees.ToList();
            }
        }

 

A couple of important things to notice here.  I am turning off proxy creation.  I have to do this, otherwise I will get serialization problems.  I am also turning off lazy loading because I do not want to populate navigation properties, plus I will get an exception if I touch that property if my code is outside of using statement.  You will see that I specify uri template as well.  I want to use meaningful path for it.  I also specify JSON format for returned data.  Let’s take a look at create method next

        [WebInvoke(UriTemplate = "/Attendee/Create", Method = "POST"
            ResponseFormat =
WebMessageFormat
.Json, 
            RequestFormat =
WebMessageFormat
.Json)]
       
public Attendee Create(Attendee
attendee)
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Attendees.Add(attendee);
                context.SaveChanges();
            }
           
return
attendee;
        }

 

 

The code to actually save attendee is pretty easy – I am utilizing entity framework code first API to add new attendee to the collection, save and return new attendee.  Entity framework will populate ID for me as part of Save method.  I also specify JSON as my format for incoming and outgoing data.  The rest of the methods are very similar, so here is entire class:

using System.Collections.Generic;
using
System.Linq;
using
System.ServiceModel;
using
System.ServiceModel.Activation;
using
System.ServiceModel.Web;
using
VSLiveData.EF;
 

namespace
WcfRestService
{
    [
ServiceContract
]
    [
AspNetCompatibilityRequirements
(
        RequirementsMode =
AspNetCompatibilityRequirementsMode
.Allowed)]
    [
ServiceBehavior(InstanceContextMode = InstanceContextMode
.PerCall)]
   
public class JSONDataService

    {
 
        [
WebGet(UriTemplate = "/Attendee/List", ResponseFormat = WebMessageFormat.Json)]
       
public List<Attendee
> GetList()
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Configuration.LazyLoadingEnabled =
false
;
                context.Configuration.ProxyCreationEnabled =
false
;
               
return
context.Attendees.ToList();
            }
        }
 
        [
WebInvoke(UriTemplate = "/Attendee/Create", Method = "POST"

            ResponseFormat =
WebMessageFormat
.Json, 
            RequestFormat =
WebMessageFormat
.Json)]
       
public Attendee Create(Attendee
attendee)
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Attendees.Add(attendee);
                context.SaveChanges();
            }
           
return
attendee;
        }
 
        [
WebGet(UriTemplate = "/Attendee/Get/{id}"

            ResponseFormat =
WebMessageFormat
.Json)]
       
public Attendee Get(string
id)
        {
           
Attendee attendee = null
;
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Configuration.LazyLoadingEnabled =
false
;
                context.Configuration.ProxyCreationEnabled =
false
;
               
int attendeeID = int
.Parse(id);
                attendee = context.Attendees.Where(one => one.AttendeeID == attendeeID).FirstOrDefault();
            }
           
return
attendee;
        }
 
        [
WebInvoke(UriTemplate = "/Attendee/Update", Method = "PUT"

            ResponseFormat =
WebMessageFormat.Json, RequestFormat = WebMessageFormat
.Json)]
       
public Attendee Update(Attendee
attendee)
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Attendees.Attach(attendee);
                context.Entry(attendee).State = System.Data.
EntityState
.Modified;
                context.SaveChanges();
            }
           
return
attendee;
        }
 
        [
WebInvoke(UriTemplate = "/Attendee/Delete/{id}", Method = "DELETE"
)]
       
public void Delete(string
id)
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
               
var attendee = new Attendee() { AttendeeID = int
.Parse(id) };
                context.Attendees.Attach(attendee);
                context.Entry(attendee).State = System.Data.
EntityState
.Deleted;
                context.SaveChanges();
            }
        }
 
    }
}

 

I have to register routes for my service in Global.asax.cs file:

using System;
using
System.ServiceModel.Activation;
using
System.Web;
using
System.Web.Routing;
 

namespace
WcfRestService
{
   
public class Global : HttpApplication

    {
       
void Application_Start(object sender, EventArgs e)
        {
            RegisterRoutes();
        }
 
       
private void
RegisterRoutes()
        {
           
RouteTable.Routes.Add(new ServiceRoute("JSONDataService", new WebServiceHostFactory(), typeof(JSONDataService
)));
        }
    }
}

 

In my web.config I just need to set my connection string for my data context and specify routing engine

 

<?xml version="1.0"?>
<configuration>
 
           <connectionStrings>
                      <add
                        name="VSLive"
                        connectionString="Server=.;Database=VSLive;Trusted_Connection=True;
"
                        providerName="System.Data.SqlClient"/>

           </connectionStrings>
 
           <system.web>
                      <compilation debug="true" targetFramework="4.0" />
           </system.web>
 
           <system.webServer>
                      <modules runAllManagedModulesForAllRequests="true">
                                 <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0,

Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
                      </modules>
           </system.webServer>
 
           <system.serviceModel>
                      <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
                      <standardEndpoints>
                                 <webHttpEndpoint>
                                            <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/>
                                 </webHttpEndpoint>
                      </standardEndpoints>
           </system.serviceModel>

 

 

Now, it is time to get to windows phone 7 app.  Just add new project and select Windows Phone 7 application.  The most interesting part is my view model that talks to my WCF service.  First of all, I am going to add a property to hold collection of attendees:

        public ObservableCollection<Attendee> Items { get; private set; }

 

Next, I am going to use WebClient to get the data.  I could also use HTTPRequest.  The difference between the two is that callbacks from WebClient are automatically marshaled to UI thread.  Here is how I would get the list of attendees:

        /// <summary>
       
/// Creates and adds a few ItemViewModel objects into the Items collection.
       
/// </summary>
       
public void LoadData()
        {
           
WebClient client = new WebClient
();
            client.OpenReadCompleted +=
new OpenReadCompletedEventHandler
(client_OpenReadCompleted);
            client.OpenReadAsync(
new Uri(@"http://localhost/WcfRestService/JSONDataService/Attendee/List"
));
 
   

        }
 
       
void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
           
ObservableCollection<Attendee> data = new ObservableCollection<Attendee
>();
           
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<Attendee
>));
           
List<Attendee> attendees = (List<Attendee
>)serializer.ReadObject(e.Result);
            attendees.ForEach(one => Items.Add(one));
 

        }

 

Let me explain what this code does.  I am creating a web client, then I am subscribing to completed event, then I am calling OpenRead.  Because of the URL I am using, this call will eventually end up in the method that matches my URL based on UriTemplate attribute for the method:

        [WebGet(UriTemplate = "/Attendee/List", ResponseFormat = WebMessageFormat.Json)]
       
public List<Attendee
> GetList()
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Configuration.LazyLoadingEnabled =
false
;
                context.Configuration.ProxyCreationEnabled =
false
;
               
return
context.Attendees.ToList();
            }
        }

 

In completed handler for read, I am using DataContractJsonSerializer to de-serialize downloaded data into List of attendees.  Then I am adding them to the items collection, which in turn is exposed to UI as following:

                <ListBox x:Name="FirstListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}" >
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Margin="0,0,0,17" Width="432" Height="78">
                                <TextBlock Text="{Binding FirstName}" TextWrapping="Wrap" 
                                         
Style="{StaticResource PhoneTextExtraLargeStyle}"/>

                                <TextBlock Text="{Binding LastName}" TextWrapping="Wrap" 
                                         
Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>

                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>

 

Next, Let’s look at the Create (Insert) method, as it demonstrates how to post data to the service.

        public void OnSaveAttendee(object parameter)
        {
           
string json = null
;
           
WebClient client = new WebClient
();
            client.Headers[
"Content-Type"] = "application/json"
;
 
           
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Attendee
));
           
using (MemoryStream stream = new MemoryStream
())
            {
                serializer.WriteObject(stream, CurrentAttendee);
                stream.Flush();
                json =
Encoding.UTF8.GetString(stream.ToArray(), 0, (int
)stream.Length);
 
            }
            client.UploadStringCompleted +=
new UploadStringCompletedEventHandler
(client_UploadStringCompleted);
            client.UploadStringAsync(
new Uri("http://localhost/WcfRestService/JSONDataService/Attendee/Create"), "POST"
, json);
        }
 
       
void client_UploadStringCompleted(object sender, UploadStringCompletedEventArgs
e)
        {
           
if (e.Error == null
)
            {
               
MessageBox.Show("OK"
);
            }
           
else

            {
               
MessageBox
.Show(e.Error.Message);
            }
 
        }

 

Now, I am reversing the order of operations.  I am serializing Attendee instance to Json, then using UTF8 encoding to convert the data to a string.  One important part to remember is to set content type on the request to JSON, otherwise you will get 404 Not Found.  In completed handler I am just checking for errors.  Again, I will end up eventually in my service’s Create method based on URI Template.

You can download entire solution here.  You will also notice that even though my classes on the client, such as Attendee:

using System.Collections.Generic;
using
System.ComponentModel;
 

namespace
VSLiveData.EF
{
   
public class Attendee : INotifyPropertyChanged

    {
       
public int AttendeeID { get; set; }
 
       
public string FirstName { get; set
; }
 
       
public string LastName { get; set
; }
 
       
public string Notes { get; set
; }
 
       
public virtual ICollection<Session> Sessions { get; set
; }
 
       
public event PropertyChangedEventHandler
PropertyChanged;
 
       
private void NotifyPropertyChanged(string
propertyName)
        {
           
PropertyChangedEventHandler
handler = PropertyChanged;
           
if (null
!= handler)
            {
                handler(
this, new PropertyChangedEventArgs
(propertyName));
            }
        }
    }
}

 

I am not calling NotifyPropertyChanged anywhere.  This is because I am using NotifyPropertyChangedWeaver, which is awesome!

Thanks.

Post to Twitter

SQL CE in Mango–Updating the Schema

In my previous post I talked about general usage of SQL CE database in Mango.  In this example I am going to talk about keeping the database schema updated.

For example, I want to add a column to Person table from previous post.  I would like to add Notes column with the following definition:

        [Column(DbType = "NVarChar(300) NULL")]

        public string Notes { get; set; }

 

Now I am going to use DatabaseSchemaUpdater class to accomplish this.  First of all, I have to add using statement to my program in order to invoke extension method on my data context:

using Microsoft.Phone.Data.Linq;

 

Now, I am going to add some code after the database exists check and add the column as follows:

                DatabaseSchemaUpdater db = App.CurrentApp.DB.CreateDatabaseSchemaUpdater();

                if (db.DatabaseSchemaVersion == 0)

                {

                    db.AddColumn<Person>("Notes");

                    db.DatabaseSchemaVersion = 1;

                    db.Execute();

                }

 

Here is what I am doing here.  I am checking for DB version, which I am going to assume responsibility for updating from now on.  I am adding notes column called Notes to Person table.  Then I am bumping version number for subsequent updates.  Lastly, I am firing Execute method to commit my changes.  Pretty easy all-and-all.  I only wish that Entity Framework code first had similar functionality.

Post to Twitter

SQL CE on Windows Phone 7.1 (Mango)

In the past I have written about dealing with data on Windows Phone 7, including WCF Services, WCF Data Services and Isolated Storage.  One thing that was missing in the initial release is native RDBMS, such as SQL CE.  Luckily, Mango update that should be released later this year finally exposes SQL CE to developers.

Even I admit that Isolated Storage DB was a useful tool for me in absence if SQL CE.  That is why I wrote my project on CodePlex.  Having said that, I would likely not take on this task if SQL CE was available in Windows Phone 7.  As a good little developer, I wanted to spend some time and educate myself on how to use SQL CE in Mango.  This post describes my adventures on the subject.

First of all, you have download and install Mango (7.1) update.  Current update version is beta 2.  You can download it here.

Now, let’s create new project and select 7.1 as target framework.  Now, let’s get acquainted with Linq to SQL API for Windows Phone 7.  Yes, interestingly enough ORM framework that is available on the phone is L2S not Entity Framework.  I will not be commenting on this subject, let’s just look at what is available.

We are using code only approach with L2S, so we are going to define some tables in code.  I want to document some relationships, so I will use the following logical structure: Person with a Title and a number of Interests.  Let’s look at the simplest table – PersonTitle.

using System.Data.Linq.Mapping;

 

namespace MangoDataApp

{

    [Table]

    public class PersonTitle

    {

        [Column(DbType = "INT NOT NULL IDENTITY", IsDbGenerated = true,

            IsPrimaryKey = true, AutoSync = AutoSync.OnInsert)]

        public int PersonTitleID { get; set; }

 

        [Column(DbType = "NVarChar(30) NOT NULL")]

        public string Title { get; set; }

    }

}

 

Let’s look at the code in details.  You will notice that I use a couple of attributes to designate this class as Table and define columns.  I find Table attribute pretty easy.  Column attribute is a lot more annoying because I have to remember the column definition and type it as a magic string.  I do not like this, but what can one do?  I designate my primary key as Identity column and force to sync up the newly generated ID after the insert is committed.  So far so good.  Now I am going to take a closer look at defining an one-to-many relationship.  I will use Person with a Title for this.  Here is what my Person class looks like:

    [Table]

    public class Person

    {

        [Column(DbType = "INT NOT NULL IDENTITY", IsDbGenerated = true,

            IsPrimaryKey = true, AutoSync = AutoSync.OnInsert)]

        public int PersonID { get; set; }

 

        [Column(DbType = "NVarChar(30) NOT NULL")]

        public string FirstName { get; set; }

 

        [Column(DbType = "NVarChar(50) NOT NULL")]

        public string LastName { get; set; }

 

        [Column()]

        public int PersonTitleID { get; set; }

 

        private EntityRef<PersonTitle> personTitle;

        [Association(ThisKey = "PersonTitleID", OtherKey = "PersonTitleID",

            Storage = "personTitle")]

        public PersonTitle PersonTitle

        {

            get { return personTitle.Entity; }

            set { personTitle.Entity = value; }

        }

 

 

As you can see above, unlike simple API of Entity Framework Code First I have to jump through a few hoops.  One thing is that I have to create an explicit backing field of type EntityRef.  I am hinting L2S to use this backing field by using Storage parameter of the column attribute.  I also specify keys in both Person and PersonTitle tables.  All-in-all not so bad.  Now let’s look at many-to-many relationship between Person and Person interests.  In this case I have to actually create a class corresponding to my junction table (unlike Entity Framework where I do not need to do this).  Here is my junction table:

using System.Data.Linq;

using System.Data.Linq.Mapping;

 

namespace MangoDataApp

{

    [Table]

    public class PersonInterest

    {

        [Column(IsPrimaryKey = true)]

        public int PersonID { get; set; }

 

        [Column(IsPrimaryKey = true)]

        public int InterestID { get; set; }

 

        private EntityRef<Interest> interest;

        [Association(ThisKey = "InterestID", OtherKey = "InterestID", Storage = "interest")]

        public Interest Interest { get { return interest.Entity; } set { interest.Entity = value; } }

 

        private EntityRef<Person> person;

        [Association(ThisKey = "PersonID", OtherKey = "PersonID", Storage = "person")]

        public Person Person { get { return person.Entity; } set { person.Entity = value; } }

    }

}

 

Again, I am using EntityRef class just like in example above.  Now, how does my Person table take use of that?

using System.Data.Linq;

using System.Data.Linq.Mapping;

 

namespace MangoDataApp

{

    [Table]

    public class Person

    {

        [Column(DbType = "INT NOT NULL IDENTITY", IsDbGenerated = true,

            IsPrimaryKey = true, AutoSync = AutoSync.OnInsert)]

        public int PersonID { get; set; }

 

        [Column(DbType = "NVarChar(30) NOT NULL")]

        public string FirstName { get; set; }

 

        [Column(DbType = "NVarChar(50) NOT NULL")]

        public string LastName { get; set; }

 

        [Association(ThisKey = "PersonID", OtherKey = "PersonID")]

        public EntitySet<PersonInterest> PersonInterests { get; set; }

 

        [Column()]

        public int PersonTitleID { get; set; }

 

        private EntityRef<PersonTitle> personTitle;

        [Association(ThisKey = "PersonTitleID", OtherKey = "PersonTitleID",

            Storage = "personTitle")]

        public PersonTitle PersonTitle

        {

            get { return personTitle.Entity; }

            set { personTitle.Entity = value; }

        }

 

        public Person()

        {

            PersonInterests = new EntitySet<PersonInterest>();

        }

    }

}

 

Pretty easy again – I define Person Interest property as EntitySet this time, not EntityRef.

Let’s take a look at our context.  This class is very simple.  Please notice that I use fields, not properties for tables.  If you use properties you will get an ugly non-descriptive exception.

using System.Data.Linq;

 

namespace MangoDataApp

{

    public class PersonContext : DataContext

    {

        public  PersonContext()

            : base("isostore:/PersonDB.sdf")

        {

 

        }

        public Table<Person> People;

        public Table<Interest> Interests;

        public Table<PersonInterest> PersonInterests;

        public Table<PersonTitle> PersonTitles;

    }

}

 

And that is all there is to it.  Now, let me see how I can pump some data into my database.  Frist of, I am going to expose my database through property of my application class:

    public partial class App : Application

    {

        private static App app;

 

        public static App CurrentApp

        {

            get { return app; }

        }

 

 

        public PersonContext DB { get; private set; }

 

        /// <summary>

        /// Constructor for the Application object.

        /// </summary>

        public App()

        {

            app = this;

            DB = new PersonContext();

 

I have a static property to make the code that uses DB easier:

            if (!App.CurrentApp.DB.DatabaseExists())

            {

                App.CurrentApp.DB.CreateDatabase();

 

Cool.  Now, let’s pump some data into my four tables:

                var int1 = new Interest() { InterestName = "Phone" };

                App.CurrentApp.DB.Interests.InsertOnSubmit(int1);

 

                var int2 = new Interest() { InterestName = "Desktop" };

                App.CurrentApp.DB.Interests.InsertOnSubmit(int2);

 

                var title = new PersonTitle() { Title = "Mr." };

                App.CurrentApp.DB.PersonTitles

                    .InsertAllOnSubmit(new[] { title, new PersonTitle() { Title = "Mrs." } });

 

                App.CurrentApp.DB.SubmitChanges();

 

                var person = new Person() { FirstName = "Sergey", LastName = "Barskiy" };

                person.PersonTitleID = title.PersonTitleID;

 

 

                App.CurrentApp.DB.People.InsertOnSubmit(person);

                App.CurrentApp.DB.SubmitChanges();

 

                PersonInterest pi1 = new PersonInterest()

{ InterestID = int1.InterestID, PersonID = person.PersonID };

                App.CurrentApp.DB.PersonInterests.InsertOnSubmit(pi1);

 

                PersonInterest pi2 = new PersonInterest()

{ InterestID = int2.InterestID, PersonID = person.PersonID };

                App.CurrentApp.DB.PersonInterests.InsertOnSubmit(pi2);

 

                person.PersonInterests.Add(pi1);

                person.PersonInterests.Add(pi2);

                App.CurrentApp.DB.SubmitChanges();

 

The last thing I would like to talk about is lazy / eager loading.  By default L2S will use lazy loading, meaning that your related properties are not retrieved until they are accessed.  Most of that time this is good, but what if I always want to load the title when I get the data?  I just use data load options object to achieve that.

                DataLoadOptions options = new DataLoadOptions();

                options.LoadWith<Person>(c => c.PersonTitle);

                App.CurrentApp.DB.LoadOptions = options;

                var people = App.CurrentApp.DB.People.ToList();

 

You can download sample project here.

Here are some useful links on MSDN:

Column attribute

Linq to SQL Overview

SQL CE Overview for Windows Phone 7.1

SQL CE Connection Strings for the Phone

Post to Twitter

Windows Phone 7 Unleashed Hackathon

Monday, May 16, 2011

6:00p.m. to 11:00 p.m.

Register:  http://bit.ly/RegWP7Hackathon

Don’t miss this opportunity to get hands on help with your Windows Phone 7 app, from the experts!

This is a "hands on" hackathon where you will learn from Windows Phone 7, XNA and Azure experts how to build, scale and publish your Windows Phone 7 app or game.  If you are just a beginner, or already have apps in the Marketplace this event will should not be missed.

BYO Laptop! 

RSVP early, space is limited to 300 attendees:  http://bit.ly/RegWP7Hackathon

Food, beverages and refreshments will be provided.

Omni Hotel At CNN Center

Grand Ballroom (A,B, C)

100 CNN Center

Atlanta, Georgia  30303

Post to Twitter

The Windows 7 Phone Sweepstakes

Between January 1, 2011 and June 30, 2011, when you develop and submit a Windows Phone 7 app into the Windows Phone Marketplace, you can be eligible for a chance to win a Windows Phone 7 (approximate retail value: $500 U.S.).

Every valid Windows Phone 7 app you submit will earn you one entry into the Sweepstakes drawing, so the more you develop, the more chances you have to win.

Here’s how it works

  1. Register for a Windows Phone Marketplace account
  2. Develop an application designed for the Windows Phone 7 platform
  3. Upload and publish your app to the Windows Phone Marketplace
  4. Fill out the form

You can use code 13VAV on that form.

The Sweepstakes starts at 12:00 a.m. local time, on January 1, 2011, and ends at 11:59 p.m. on June 30, 2011 ("Promotion Period"). The Promotion Period will consist of three (3) separate Entry Periods as follows:

January 1, 2011 – January 31, 2011
February 1, 2011 – March 31, 2011
April 1, 2011 – June 30, 2011

Entries will be eligible for the Entry Period during which they are received only and will not carry over to subsequent Entry Periods. You must enter each Entry Period separately.

For complete contest rules, please visit WindowsPhone7event.com/contestrules.

Post to Twitter

Quick Start Guide for Windows Phone 7 Database

I have a CodePlex project for Isolated Storage based database for Windows phone 7.  You can check out this project at http://winphone7db.codeplex.com/

 

First step is to download the project and build it on your copter.  Visit the download page for the latest recommended download.  Unzip the source code on your machine, open it up in Visual Studio 2010 and compile to create a DLL.

Next, create new Windows Phone 7 project and add a reference to the DLL from step 1.

Next, in your View Model (or elsewhere in your application) check for database existence and create if it does not exist along with tables.  See sample code below

            if (!Database.DoesDatabaseExists(DatabaseName))
            {
                database =
Database
.CreateDatabase(DatabaseName);
                database.CreateTable<
Person
>();
                database.CreateTable<
PersonDetail
>();
                database.Save();
            }
           
else
            {
                database =
Database.OpenDatabase(DatabaseName, string.Empty, true);
            }

In the sample above I am testing if database exists, then create it if it does not,  Then I am adding two tables to it based on POCO classes.  For example, Person class would look like

    public class Person
    {
       
public Guid PersonID { get; set
; }
       
public string FirstName { get; set
; }
       
public string LasstName { get; set; }
    }

 

If you would like to add a row to a table, just issue Add command:

db.Table<Person>().Add(NewPerson());

 

New Person routine just returns Person instance.

To remove, just issue remove command:

 

db.Table<Person>().Remove(person2);

 

You can also remove and add a range of items based on condition.

db.Table<Person>().RemoveRange((person) => { return (person.Salary >= 2); });

 

You can also add a range of items, specifically IEnumerable<T>

db.Table<Person>().AddRange(list);

 

Make sure to call Save() on either database or a specific table to commit your changes.

You can also look in unit test project that is distributed as part of the source code download for other API samples.

Post to Twitter

Working with Data on Windows Phone 7 – Part 1

I am starting a short series of blog posts that will go over various techniques of working with data on Windows Phone 7.  I am going to create a Silverlight application for the phone that gets local and remote data in a number of ways.

I this first post I will build a WCF service and connect to it from phone application.  I am going to use Entity Framework Code Frist approach to expose the data through my WCF Service.

Let’s get started.

Step 1

I am going to create new phone application.  Start Visual Studio 2010 and create new project.  Select a project template for Windows Phone Pivot Application.

image

Now, I forget about pre-generated code and create a WCF service.  To do so, add new project to created solution.  To give you a head start, select template for WCF Service Application.

image

Now, it is time to get Entity Framework code first CTP 5 up and going to create database and access it.  I am going to use NuGet (install it first if you do not have it).  Right click on references in your WCF project and select add Package References.  Choose to search on line and first the CTP 5.

image

I am installing the package which will download the DLL and add references to my project.  I am also adding a reference to System.ComponentModel.DataAnnotations.

Now I am going to add my EF classes, which are POCO classes.  I am going to go for something simple, so I am creating new single object called Person along with my data context.  Person class is very simple and here is the code for it.

using System;
using System.ComponentModel.DataAnnotations;
using
System.Runtime.Serialization;
 

namespace
WcfPhoneService
{
    [
DataContract
]
   
public class Person
    {
        [
Key
]
        [
Required
]
        [
DataMember
]
       
public Guid PersonID { get; set
; }
 
        [
MaxLength
(30)]
        [
Required
]
        [
DataMember
]
       
public string FirstName { get; set
; }
 
        [
MaxLength
(30)]
        [
Required
]
        [
DataMember
]
       
public string LastName { get; set; }
    }
}

 

There are a couple of points worth noticing.  I am using data annotation attributes to denote the requirement of all my future columns in the table.  I am setting the maximum length as well as the key for the table.  I am also setting the WCF required attributes as I am going to be eventually transferring these classes to/from the phone application.  I also need to create the data context, akin to database that will contain my list of persons.  It inherits from base class in EF CTP 5 and contains the list (set) of persons.  Again. code is pretty simple:

using System.Configuration;
using System.Data.Entity;
using
System.Data.Entity.Database;
 

namespace
WcfPhoneService
{
   
public class PersonContext : DbContext
    {
       
public
PersonContext()
        {
           
//Set initializer to handle model changes
            DbDatabase.SetInitializer<PersonContext>(new PersonContextConfig
());
 
           
this
.Database.Connection.ConnectionString =
                   
ConfigurationManager.ConnectionStrings["PersonConnectionString"
]
                    .ConnectionString;
        }
 
       
/// <summary>
        /// List of persons
        /// </summary>
        public IDbSet<Person> Persons { get; set
; }
 
       
/// <summary>
        /// Add custom configurations if necessary
        /// </summary>
        /// <param name="modelBuilder">Model builder</param>
        protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder
modelBuilder)
        {
           
base.OnModelCreating(modelBuilder);
 
        }
    }
}

 

You can see an extra class in the constructor called PersonContextConfig.  This class simply controls the default database behavior of the context when the model changes.  I am setting it to recreating of the database in my case.  I also added a couple of rows of data just for the demo by overriding Seed method.

using System.Data.Entity.Database;
using
System;
 

namespace
WcfPhoneService
{
   
public class PersonContextConfig : DropCreateDatabaseIfModelChanges<PersonContext
>
    {
       
protected override void Seed(PersonContext
context)
        {
           
base
.Seed(context);
            context.Persons.Add(
new Person() { PersonID = Guid.NewGuid(), FirstName = "John", LastName = "Doe"
});
            context.Persons.Add(
new Person() { PersonID = Guid.NewGuid(), FirstName = "Jane", LastName = "Doe" });
            context.SaveChanges();
        }
    }
}

 

Now, it is time to create my service.  I am going to add just two methods to it – get list of persons and insert a new person.  When project was created, it created default IService1 interface and Service1 implementation.  I am just going to rename both to IPersonService and PersonService respectively.  Then, I am going to implement the two methods above

using System.Collections.Generic;
using
System.ServiceModel;
 

namespace
WcfPhoneService
{
    [
ServiceContract
]
   
public interface IPersonService
    {
        [
OperationContract
]
       
IEnumerable<Person
> GetPeople();
 
        [
OperationContract
]
       
void AddPerson(Person person);
    }
 
 
 
}

 

using System.Collections.Generic;
using
System.Linq;
 

namespace
WcfPhoneService
{
 
   
public class PersonService : IPersonService
    {
       
public IEnumerable<Person
> GetPeople()
        {
           
using (PersonContext context = new PersonContext
())
            {
               
return
context.Persons.OrderBy(one => one.LastName).ThenBy(one => one.FirstName).ToList();
            }
        }
 
       
public void AddPerson(Person
person)
        {
           
using (PersonContext context = new PersonContext())
            {
                context.Persons.Add(person);
                context.SaveChanges();
            }
        }
    }
}

 

Pretty simple, right.  Now I am going to switch to my Phone project.  I am going to remove all pre-generated code from all view models first and build the project to make sure it is all good.  Now, it is time to add a service reference to my WCF project.  To do so, right click on references node in phone project and choose add service reference menu item.  Click on Discover button on the service dialog box.  Change namespace to PersonService for consistency.

image

Click OK and let the studio generate all your code for you.  To see generated code, click on PersonService reference under service references, then click on Show All Files on top of Solution explorer window.  You can then drill down to see Reference.cs.  This contains all your generated code.

image

I am now going to update view model to let it connect to the service and get the list of people.  I have to create an instance of the client (proxy), setup a handler for GetPeople method, then call it.  I also add a property to hold Person collection in.  All fairly simple.  Here is the entire code:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using
WindowsPhonePivotAppWithData.PersonService;
 
 

namespace
WindowsPhonePivotAppWithData
{
   
public class MainViewModel : INotifyPropertyChanged
    {
        PersonService.
PersonServiceClient client = new PersonService.PersonServiceClient
();
       
public
MainViewModel()
        {
 
        }
 
       
private ObservableCollection<Person
> people;
 
       
public ObservableCollection<Person
> People
        {
           
get { return
people; }
           
private set { people = value; NotifyPropertyChanged("People"
); }
        }
 
       
public void
LoadData()
        {
            client.GetPeopleCompleted += client_GetPeopleCompleted;
            client.GetPeopleAsync();
        }
 
       
void client_GetPeopleCompleted(object sender, PersonService.GetPeopleCompletedEventArgs
e)
        {
           
if (e.Error != null
)
            {
               
MessageBox
.Show(e.Error.ToString());
            }
           
else
            {
                People = e.Result;
            }
        }
 
 
       
public event PropertyChangedEventHandler
PropertyChanged;
       
private void NotifyPropertyChanged(String
propertyName)
        {
           
PropertyChangedEventHandler
handler = PropertyChanged;
           
if (null
!= handler)
            {
                handler(
this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

 

The last part is to modify the MainPage.xaml and update item template to point to the properties that belong to person class, namely last name and first name.

        <controls:Pivot Title="MY APPLICATION">
            <!–Pivot item one–>
            <controls:PivotItem Header="first">
                <!–Double line list with text wrapping–>
                <ListBox x:Name="FirstListBox" Margin="0,0,-12,0"
 
                       
ItemsSource="{Binding People}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                          <StackPanel Margin="0,0,0,17" Width="432">
                              <TextBlock
 
                                
Text="{Binding FirstName}"
 
                                
TextWrapping="Wrap"
 
                                
Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                              <TextBlock
 
                                
Text="{Binding LastName}"
 
                                
TextWrapping="Wrap"
 
                                
Margin="12,-6,12,0"
 
                                
Style="{StaticResource PhoneTextSubtleStyle}"/>
                          </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </controls:PivotItem
>

 

Now we will just call LoadData from the code behind of MainPage.  This is just a temporary fix, ordinarily I would have the view / view model hook up elsewhere.

    public partial class MainPage : PhoneApplicationPage
    {
       
// Constructor
        public
MainPage()
        {
            InitializeComponent();
 
            DataContext =
App
.ViewModel;
           
App.ViewModel.LoadData();
        }
    }

 

That was the last part.  Now we can run the phone application in the emulator.  And we should be able to see the list of two people that were inserted in Seed() method above.

To summarize, we just consumed WCF service from the phone.  To call the same from a deployed application, we will need to change the address in ServiceReference.ClientConfig file.  That is it.

The other part I would like to try is to insert a new person.  I am going to add a button to the second pivot item and call the insert method.  I am going to just use code behind, but you can look at my past posts on how do use MVVM Light to wire up commands.

            <controls:PivotItem Header="second"> 
                <Grid>
                    <Button
 
                      
Content="Insert Person"
 
                      
Click="Button_Click"
 
                      
Width="200"
 
                      
Height="100"/>
                </Grid>
            </controls:PivotItem
>

 

Here is the code in the view model that I need to add:

        public void InsertPerson()
        {
            client.AddPersonAsync(
new Person
() 
            { PersonID =
Guid.NewGuid(), FirstName = "John", LastName = "Johnson" });
        }

 

Here is the final code for my view model:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using
WindowsPhonePivotAppWithData.PersonService;
 
 

namespace
WindowsPhonePivotAppWithData
{
   
public class MainViewModel : INotifyPropertyChanged
    {
        PersonService.
PersonServiceClient
client;
       
public
MainViewModel()
        {
            client =
new PersonService.PersonServiceClient
();
            client.AddPersonCompleted += client_AddPersonCompleted;
            client.GetPeopleCompleted += client_GetPeopleCompleted;
        }
 
       
private ObservableCollection<Person
> people;
 
       
public ObservableCollection<Person
> People
        {
           
get { return
people; }
           
private set { people = value; NotifyPropertyChanged("People"
); }
        }
 
       
public void
LoadData()
        {
 
            client.GetPeopleAsync();
        }
 
       
void client_GetPeopleCompleted(object sender, PersonService.GetPeopleCompletedEventArgs
e)
        {
           
if (e.Error != null
)
            {
               
MessageBox
.Show(e.Error.ToString());
            }
           
else
            {
                People = e.Result;
            }
        }
 
       
public void
InsertPerson()
        {
            client.AddPersonAsync(
new Person
() 
            { PersonID =
Guid.NewGuid(), FirstName = "John", LastName = "Johnson"
});
        }
 
       
void client_AddPersonCompleted(object sender, AsyncCompletedEventArgs
e)
        {
           
if (e.Error != null
)
            {
               
MessageBox
.Show(e.Error.ToString());
            }
           
else
            {
               
MessageBox.Show("Succecss adding person"
);
                client.GetPeopleAsync();
            }
        }
 
       
public event PropertyChangedEventHandler
PropertyChanged;
       
private void NotifyPropertyChanged(String
propertyName)
        {
           
PropertyChangedEventHandler
handler = PropertyChanged;
           
if (null
!= handler)
            {
                handler(
this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

 

And that is all there is to it.  We created a WCF service and consumed it from Windows phone application.  I used Entity Framework code first to create classes and I used the same classed as data contract for my service.  In the next post of this short series I will work on consuming a custom OData service.

Post to Twitter

My Applications in App Store for Windows Phone 7

I checked the download statistics of my applications for Windows Phone 7 in the App Store, and to my surprise I have quite a few downloads!  Mr.  Fortune’s Famous Quotes is a free application that generates a random famous quote on demand, accompanied by a cool animation effect.  As you can see, that application has been downloads 242 times between 12/29/2010  and 1/3/2011.  I published it on 12/29/2010.  Apparently, Windows phone users like quotes.  On top of that, my paid application ($0.99 total cost) – Sport Timer, was downloaded once, which technically infinity times better result than I expected.  This is pretty cool app, actually.  It allows you to enter multiple people, multiple events, includes stop watch, and maintains history of all recorded times.  It provides text view and graph view of results for each person/even type combination.

 

Here is the screenshot with stats from the App Hub.

image

Post to Twitter

Windows Phone 7 Controls Project Update

I have published an update to the calendar control on my CodePlex project dedicated to building common controls for Windows Phone 7.

I added a number of new features.  The biggest improvement added is the ability to use context menu from Silverlight Toolkit for Windows Phone 7.  In order to provide this feature, I added style property to Calendar control that allows you to specify a custom template for calendar item.  Of course, you have to be careful not to override parts of the template that are responsible for providing color information for the calendar.  Namely, in your template you have to have TemplateBinding for Foreground and Background.  Other than that, you can modify the default template as you see fit.  Then, you can set CalendarItemsStyle property on the calendar to force it to use different template.  Here is the example of the XAML for the screen that adds context menu to the calendar items.  As you see below I specify style for CalendarItem in the resources of the page, then use this style and assign it to CalendarItemStyle property of the calendar control.

<phone:PhoneApplicationPage 
  
x:Class="Sample.MainPage"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
   xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
   xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 
  
xmlns:wi="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    
  
xmlns:i="clr-namespace:Microsoft.Practices.Prism.Interactivity;assembly=Microsoft.Practices.Prism.Interactivity"
 
  
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
   xmlns:mvvmLight="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP7"
   xmlns:wpControls="clr-namespace:WPControls;assembly=WPControls"
   mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
 
  
FontFamily="{StaticResource PhoneFontFamilyNormal}"
   FontSize="{StaticResource PhoneFontSizeNormal}"
   Foreground="{StaticResource PhoneForegroundBrush}"
   SupportedOrientations="Portrait"  Orientation="Portrait"
   shell:SystemTray.IsVisible="True">
    <phone:PhoneApplicationPage.Resources>
        <Style TargetType="wpControls:CalendarItem" x:Key="ItemStyle">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate  TargetType="wpControls:CalendarItem">
                        <Grid x:Name="OuterGrid" HorizontalAlignment="Stretch"
 

VerticalAlignment="Stretch">
                            <Border
 
                          
BorderThickness="2"
                           HorizontalAlignment="Stretch"
                           VerticalAlignment="Stretch"
                           BorderBrush="{StaticResource PhoneForegroundBrush}">
                                <Grid Height="60" HorizontalAlignment="Stretch"
 

VerticalAlignment="Stretch" >
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto"/>
                                        <RowDefinition Height="*"/>
                                    </Grid.RowDefinitions>
                                    <Rectangle Grid.RowSpan="2"
 

x:Name="BackgroundRectangle" Fill="{TemplateBinding Background}" />
                                    <TextBlock
 
                                  
x:Name="DayNumberBlock"
                                   Text="{Binding Path=DayNumber,
 

RelativeSource={RelativeSource TemplatedParent}}" 
                                  
Foreground="{TemplateBinding Foreground}"
 
                                  
FontWeight="ExtraBold"
                                   HorizontalAlignment="Left"
 
                                  
VerticalAlignment="Top"
 
                                  
Margin="4,2,0,0"/>
 
                                </Grid>
                            </Border>
                            <toolkit:ContextMenuService.ContextMenu>
                                <toolkit:ContextMenu>
                                    <toolkit:MenuItem Header="Mark">
                                        <wi:Interaction.Triggers>
                                            <wi:EventTrigger EventName="Click">
                                                <mvvmLight:EventToCommand
 

Command="{Binding Path=MarkCommand, Mode=OneWay}" 

CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ItemDate}" />
                                            </wi:EventTrigger>
                                        </wi:Interaction.Triggers>
                                    </toolkit:MenuItem>
                                    <toolkit:MenuItem Header="Clear">
                                        <wi:Interaction.Triggers>
                                            <wi:EventTrigger EventName="Click">
                                                <mvvmLight:EventToCommand
 

Command="{Binding Path=ClearCommand, Mode=OneWay}" 

CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ItemDate}" />
                                            </wi:EventTrigger>
                                        </wi:Interaction.Triggers>
                                    </toolkit:MenuItem>
                                </toolkit:ContextMenu>
                            </toolkit:ContextMenuService.ContextMenu>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </phone:PhoneApplicationPage.Resources>
 
    <!–LayoutRoot is the root grid where all page content is placed–>
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <!–Pivot Control–>
        <controls:Pivot Title="Sample">
 
            <controls:PivotItem Header="calendar">
                <Grid>
                    <wpControls:Calendar x:Name="mainCalendar"
 
                                       
SelectedDate="{Binding Path=SelectedDate, Mode=TwoWay}"
 
                                       
CalendarItemStyle="{StaticResource ItemStyle}"
                                        DatesSource="{Binding Path=Dates}"
                                        ColorConverter="{Binding}"/>
                </Grid>
 
            </controls:PivotItem>
 
            <controls:PivotItem Header="other">
                <Grid>
 
                </Grid>
            </controls:PivotItem>
        </controls:Pivot>
    </Grid>
 

 
</phone:PhoneApplicationPage
>

 

To make this XAML work, you have to also add references to MVVM Light framework for the phone in addition to Silverlight toolkit for the phone.  ViewModel is very simple, but I want to paste entire code to make it very clear how it is used.

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows.Media;
using GalaSoft.MvvmLight.Command;
using PeriodTracker.ViewModels;
using
WPControls;
 
 

namespace
Sample
{
   
public class MainViewModel : INotifyPropertyChanged, IDateToBrushConverter
    {
       
public
MainViewModel()
        {
            Dates =
new ObservableCollection<ISupportCalendarItem
>();
            Dates.Add(
new DateInfo() { CalendarItemDate = DateTime
.Today });
            Dates.Add(
new DateInfo() { CalendarItemDate = DateTime
.Today.AddDays(1) });
            MarkCommand =
new RelayCommand<object
>(OnMark);
            ClearCommand =
new RelayCommand<object
>(OnClear);
        }
 
       
public RelayCommand<object> MarkCommand { get; set
; }
       
public void OnMark(object
item)
        {
           
if (!Dates.Where(one => one.CalendarItemDate == (DateTime
)item).Any())
            {
                Dates.Add(
new DateInfo() { CalendarItemDate = (DateTime
)item });
            }
        }
 
       
public RelayCommand<object> ClearCommand { get; set
; }
       
public void OnClear(object
item)
        {
           
ISupportCalendarItem info = Dates.FirstOrDefault(one => one.CalendarItemDate == (DateTime
)item);
           
if (info != null
)
            {
                Dates.Remove(info);
            }
        }
 
       
private DateTime
selectedDate;
 
       
public DateTime
SelectedDate
        {
           
get { return
selectedDate; }
           
set { selectedDate = value; NotifyPropertyChanged("SelectedDate"
); }
        }
 
       
public event PropertyChangedEventHandler
PropertyChanged;
       
private void NotifyPropertyChanged(String
propertyName)
        {
 
           
if (PropertyChanged != null
)
            {
                PropertyChanged(
this, new PropertyChangedEventArgs
(propertyName));
            }
        }
 
       
private ObservableCollection<ISupportCalendarItem
> dates;
 
       
public ObservableCollection<ISupportCalendarItem
> Dates
        {
           
get { return
dates; }
           
set { dates = value; NotifyPropertyChanged("Dates"
); }
        }
 
       
public Brush Convert(DateTime dateTime, bool isSelected, Brush defaultValue, BrushType
brushType)
        {
           
if (brushType == BrushType
.Background)
            {
               
if (Dates != null
&& Dates.Where(one => one.CalendarItemDate == dateTime).Any() && !isSelected)
                {
                   
return new SolidColorBrush(Colors
.Red);
                }
               
else
                {
                   
return
defaultValue;
                }
            }
           
else
            {
               
if (Dates != null
&& Dates.Where(one => one.CalendarItemDate == dateTime).Any() && isSelected)
                {
                   
return new SolidColorBrush(Colors
.Red);
                }
               
else
                {
                   
return defaultValue;
                }
            }
        }
    }
}

 

As you can see, I have a property that provides source with dates to the calendar.  This is also new in this release.  If you provide an Observable Collection where each item implements new interface ISupportCalendarItem, calendar can improve overall performance.  It also enables you not to explicitly raise property changed events, forcing control to repaint.  Having said that, you now have two ways to explicitly force repaint of the calendar.  You can call Refresh() method on it.  Or, in your view model you can raise property changed event for the property that is bound to the DatesSource property of the calendar.

Another change I introduce is consolidate date to brush converters into a single class.  This minimizes the code you have write as well as simplifies XAML at the same time.  Here is the new interface:

using System.Windows.Media;
using
System;
 

namespace
WPControls
{
   
/// <summary>
    /// This converter can be used to control day number color and background color
    /// for each day
    /// </summary>
    public interface IDateToBrushConverter
    {
       
/// <summary>
        /// Perform conversion of a date to color
        /// This can be used to color a cell based on a date passed it
        /// </summary>
        /// <param name="dateTime">Date for the calendar cell</param>
        /// <param name="isSelected">Indicates if a date is selected by the user</param>
        /// <param name="defaultValue">Brush that will be used by default
        /// if the converter did not exists
        /// </param>
        /// <param name="brushType">Type of conversion to perform – foreground or background</param>
        /// <returns>New Brush to color day number or calendar cell background</returns>
        Brush Convert(DateTime dateTime, bool isSelected, Brush defaultValue, BrushType brushType);
    }
}

 

Brush type is the enumeration that consists of background and foreground:

namespace WPControls
{
   
/// <summary>
    /// Type of brush to driver color converter
    /// </summary>
    public enum BrushType
    {
       
/// <summary>
        /// Calendar item background conversion
        /// </summary>
        Background,
       
/// <summary>
        /// Day number of calendar item
        /// </summary>
        Foreground
    }
}

 

This concludes the list of changes in this release.  Please let me know if you have any questions at all regarding the use of the control

Post to Twitter

Windows Phone 7 Project

I started new CodePlex project for controls for Windows Phone 7.  One control I needed for my next application is calendar control.  I could not find one, so I started thinking about one a little while ago.  Today I published an alpha version of calendar control.  You can find it here http://wpcontrols.codeplex.com/.

Calendar control supports the following features in the initial release:

  • Next/Previous month buttons
  • Ability to provide converters to color day number or date cell background
  • Ability to select a date and apply background color
  • Data binding to SelectedDate

Calendar also supports the following events

  • MonthChanging is fired before calendar is rebuilt for the next month. Can be used to setup data for converters
  • MonthChanged is fired after calendar is rebuilt for new month/year
  • SelectionChanged is fired when a user selects a date

As part of download, you are provided with a working sample that shows how to do converters and calendar control without converters.

Here is the markup you can use in both cases:
Sample calendar control:

xmlns:wpControls="clr-namespace:WPControls;assembly=WPControls"
<wpControls:Calendar x:Name="Cal"/>

 

 


Using converters:

    <phone:PhoneApplicationPage.Resources>

        <local:BackgroundConverter x:Key="BackgroundConverter"/>

        <local:DayNumberConverter x:Key="DayNumberConverter"/>

    </phone:PhoneApplicationPage.Resources>

<wpControls:Calendar      x:Name="Cal"
    BackgroundConverter="{StaticResource BackgroundConverter}"
    ForegroundConverter="{StaticResource DayNumberConverter}"
    MonthChanged="Cal_MonthChanged"
    MonthChanging="Cal_MonthChanging"
    SelectionChanged="Cal_SelectionChanged"
    />

Converter simply have to implement a simple interface with one method:

image

Of course, instead of hard-coded date you can drive them based off your data on the phone.  On a second note, if you need a simple, easy to use, yet powerful database for your Windows Phone 7 application, check out my other project on CodePlex: http://winphone7db.codeplex.com/

Here is what the control looks like on the phone:

CalendarControl.png

Post to Twitter

Building Windows Phone 7 Silverlight Application

It this post I want to describe the process I went though building and publishing my first Silverlight application for Windows Phone 7.  It is currently being tested, and I hope I will pass the test this time.  I went through a couple of iterations of testing already, learning in the process from my mistakes.  I want to describe the process so that I myself can remember the steps, but hopefully help other folks with some tips and tricks.

In order to be able to publish an application for Windows Phone 7, you must sign up as a developer on App Hub – http://create.msdn.com.  This process was pretty painless actually, and only took a few minutes.  A couple of important things to remember.  Once you sign up, you will get an email from GeoTrust.  You have to follow the link in the email and answer a few questions confirming your identity.  The questions for me came from my credit report.  This tells me that Microsoft really wants to ensure there is a real person behind the signee.  Once you complete this step, you have to go back to App Hub and fill out your bank account information.  Once you are done with paperwork, you are ready to start writing your application.

To create an app, you have to have some tools installed on your machine.  You have to have at lest Visual Studio Express for Windows Phone, but I would also recommend Expression Blend for Windows Phone 7.  You can find the links to the software on main page of App Hub.

Once you have basic tools, you will likely need some secondary software to help you write your applications.  Here is what I would recommend.

  • Windows Phone 7 Toolkit from CodePlex.  Controls in the toolkit are written by Microsoft folks just like Silverlight toolkit.  You can download the toolkit here  To help you get started, check out Tim Heuer’s post on the toolkit here.
  • Another good tool is version of Prism for Windows Phone 7.  This article on MSDN describes the content of Prism for the phone.  You can download binaries here.  Once you build Prism 4, you will find Phone folder under Bin with all the binaries.  There is a lot of cool functionality there.
  • I had some troubles getting commanding to work using blend using event to command behavior.  As a result, I also downloaded and used MVVM Light by Laurent Bugnion.  You can download binaries and find some quick start links on CodePlex here.
  • If you want to save some data on the phone, I would recommend using a database abstraction by your truly.  You can download Database for Windows Phone 7 here.

Now, some sample code.

Application bar is the portion of the screen that shows the menu.  I am using Prism to implement commands to react to user interactions.  Here is XAML portion of the application bar.

<phone:PhoneApplicationPage
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
   xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
   xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 
  
xmlns:wi="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    
  
xmlns:i="clr-namespace:Microsoft.Practices.Prism.Interactivity;assembly=Microsoft.Practices.Prism.Interactivity"
 
  
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
   xmlns:mvvmLight="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP7"
   xmlns:charting="clr-namespace:System.Windows.Controls.DataVisualization.Charting;

assembly=System.Windows.Controls.DataVisualization.Toolkit"
   x:Class="SportTimer.MainPage"
 
  
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="696"
 
  
FontFamily="{StaticResource PhoneFontFamilyNormal}"
   FontSize="{StaticResource PhoneFontSizeNormal}"
   Foreground="{StaticResource PhoneForegroundBrush}"
   SupportedOrientations="Portrait"  Orientation="Portrait"
   shell:SystemTray.IsVisible="True">
 
    <!–Sample code showing usage of ApplicationBar–>
    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton IconUri="/icons/clock.png" Text="time" />
            <shell:ApplicationBarIconButton IconUri="/icons/person.png" Text="people"/>
            <shell:ApplicationBarIconButton IconUri="/icons/event.png" Text="events"/>
            <shell:ApplicationBarIconButton IconUri="/icons/graph.png" Text="history"/>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>
 
    <wi:Interaction.Behaviors>
        <i:ApplicationBarButtonCommand ButtonText="time" 

CommandBinding="{Binding ChangeIndexCommand, Mode=OneWay}" 

CommandParameterBinding="{Binding TimeIndex}"/>
        <i:ApplicationBarButtonCommand ButtonText="people" 

CommandBinding="{Binding ChangeIndexCommand, Mode=OneWay}" 

CommandParameterBinding="{Binding PeopleIndex}"/>
        <i:ApplicationBarButtonCommand ButtonText="events" 

CommandBinding="{Binding ChangeIndexCommand, Mode=OneWay}" 

CommandParameterBinding="{Binding EventIndex}"/>
        <i:ApplicationBarButtonCommand ButtonText="history" 

CommandBinding="{Binding ChangeIndexCommand, Mode=OneWay}" 

CommandParameterBinding="{Binding HisotryIndex}"/>
    </wi:Interaction.Behaviors>
    <!–LayoutRoot is the root grid where all page content is placed–>
    <Grid x:Name="LayoutRoot" Background
="Transparent">

 

Let me comment a bot on the code.  Application bar can have at most 4 buttons, and I am using all of them.  I am declaring application bar button command separately which is how Prism wants the implementation done, then bind commands to buttons via Text property of the button. Commands are declared in my view model as follows

 

        public DelegateCommand<object> ChangeIndexCommand { get; set; }        public void OnChangeIndex(object parameter)        {            SelectedPivotIndex = int.Parse(parameter.ToString());        }

 

ChangeIndexCommand = new DelegateCommand<object>(OnChangeIndex);

I am creating an instance of the command in view model constructor.  The command simply changes selected index of the pivot control,

I also have some button controls in my application.  I use MVVM light for those, again because I could not get Prism behavior to work.

<Button Content="Stop" Grid.Row="3" Grid.Column="2">    <wi:Interaction.Triggers>        <wi:EventTrigger EventName="Click">            <mvvmLight:EventToCommand Command="{Binding Path=StopTimerCommand}" />        </wi:EventTrigger>    </wi:Interaction.Triggers></Button>

 

Another interesting control I use is ContextMenu from toolkit.  I am using it to delete items from ListBox:

<ListBox x:Name="FilteredHistoryListBox" Grid.Row="3" Grid.ColumnSpan="3"

           ItemsSource="{Binding Path=FilteredHistory}">

    <ListBox.ItemTemplate>

        <DataTemplate>

            <Border Margin="0" BorderThickness="0" Background="Transparent" Padding="0">

                <toolkit:ContextMenuService.ContextMenu>

                    <toolkit:ContextMenu>

                        <toolkit:MenuItem Header="Delete">

                            <wi:Interaction.Triggers>

                                <wi:EventTrigger EventName="Click">

                                    <mvvmLight:EventToCommand 

Command="{Binding ElementName=EventsItem, Path=DataContext.DeleteHistoryCommand, Mode=OneWay}" 

CommandParameter="{Binding}" />

                                </wi:EventTrigger>

                            </wi:Interaction.Triggers>

                        </toolkit:MenuItem>

                    </toolkit:ContextMenu>

                </toolkit:ContextMenuService.ContextMenu>

                <StackPanel Margin="0,0,0,7">

                    <TextBlock Text="{Binding Path=TimeString}"  

TextWrapping="NoWrap" Margin="12,0,0,0" Style="{StaticResource PhoneTextExtraLargeStyle}"/>

                    <TextBlock Text="{Binding Path=HistoryDateString}" TextWrapping="NoWrap" Margin="12,-6,0,0" Style="{StaticResource PhoneTextSubtleStyle}"/>

                </StackPanel>

            </Border>

        </DataTemplate>

    </ListBox.ItemTemplate>

 

 

Now, about application bar icons.  I was trying to use the icons from Visual Studio, and I failed the test.  Then, I actually read the documentation Smile

The application bar icons must be 48×48 pixels with transparent background, with the icon itself (image or text) white 24×24 pixels.  I found this very good post by Brad Tutterow, and I used it to create custom icons for my application.  Nothing fancy, but my skill were good enough to create four icons for my Sport Timer application.   Make sure to test your application in light theme either on the phone or emulator.  Here is my person icon and graph icon.

Persongraph

I wanted to incorporate graphs info my application, and I found this great port of chart library from Silverlight toolkit.  At least I think that is what it is.  Here is the link to the post about it that includes download link.

Another tip that I have is that for some reason virtual keyboard did not work on one of my screens.  Come to find out through trial and error that you must inherit for PhoneApplicationPage for that to work.  I used UserControl, following typical Silverlight development pattern.  Once I changed the inheritance in XAML and .cs files, everything worked like magic.

Also, you have to test your icons on the phone.  Make sure to pin your application to start up to ensure it looks good.  You can setup icons and test for start up page on the phone and regular list on the phone in properties of your application page.  Make sure to check these settings.

image

You can use the same image or different ones.  I followed the default application and used different sizes.  You can see the image size from the icon name.  All of them are images in png format.

When you submit your application, you are also required to submit a number of image in specific format.  I used Paint.NET to resize my images and set DPI.  You can do both through Resize command window.  Also, make sure the screenshots of your application do not include the emulator itself, only the application.  You will fail testing because of the this as well.  Again, follow the descriptions in submission page to verify the DPI and sizes of all your images.

I hope this post may save a few folks a few extra minutes.

Post to Twitter

Back to Windows Phone 7 Database

Since Microsoft now released RTM version of their tools for Windows Phone 7 development, I updated my phone database project to the latest version as well.  You can find this project here : http://winphone7db.codeplex.com/.

I added also a new feature – ability to create tables with data on desktop, then load them into the database when application runs for the first time.  In order to optimize the process, I am setting this table content (XML files) as Content in my sample application.  If you set your additional files as resources, they will be immediately loaded into memory, while this is not the same for files marked as content.  Here is a screenshot that illustrates the settings.

image

Next step is to read content in Windows phone 7 application.  Here is how I am doing it:

string

content = string.Empty;
Uri uri = new Uri(“test.xml”, UriKind.Relative);
StreamResourceInfo info = Application.GetResourceStream(uri);
using (StreamReader reader = new StreamReader(info.Stream))
{
    content = reader.ReadToEnd();
}

 

 

Pretty easy, hah?

Please look at downloaded application at http://winphone7db.codeplex.com/. for sample use of my database.

Thanks.

Post to Twitter

Windows Phone 7 Beta is here

Windows Phone 7 Developer tool beat has been released by Microsoft.  You can download it here.
Make sure to download and read release note available on the page above.

 

Thanks.

Post to Twitter

Windows Phone 7 Database

I just uploaded and published new CodePlex project I have been working on.  It is an Isolated Storage based database for Windows Phone 7.  I converted my existing Silverlight database project I published a long time ago and adapted it to Windows Phone 7. It supports multiple strongly typed tables, basic Linq based operations, addition and deletion of ranges of items, deletion of items based on condition.  You can also directly bind data to UI in Silverlight because base table inherits from ObservableCollection.  It supports encryption along with lazy loading of table. 

Please take a look at http://winphone7db.codeplex.com/

 

Here are key classes of the project.  ITable interface makes it easy to write generic code in Database class.  It is a simple interface as you can see:

using System;
using System.IO;

namespace SilverlightPhoneDatabase.Core
{
    /// <summary>
    /// Interface that is used for tables in a database
    /// </summary>
    public interface ITable
    {
        /// <summary>
        /// Type of object that database contains
        /// </summary>
        Type RowType { get; }

        /// <summary>
        /// Save table le to the Isolated Storage
        /// </summary>
        void Save();

        /// <summary>
        /// Write content of a table to a file stream
        /// </summary>
        /// <param name="stream">Stream to write table to</param>
        void WriteDTableToStream(Stream stream);

        /// <summary>
        /// Set internal variables data when a table is de-serialized
        /// </summary>
        /// <param name="databaseName">Database name that table belongs to</param>
        /// <param name="password">Password to use for encryption</param>
        void SetTableDefinition(string databaseName, string password);
    }
}

I use XML Serializer to store table to Isolated Storage:

using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
                    {
                        string fileName = string.Concat(_databaseName, ".", typeof(T).FullName);
#if SILVERLIGHT
                        if (store.FileExists(fileName))
                        {
                            store.DeleteFile(fileName);
                        }
#else
                        if (store.GetFileNames(fileName).Length > 0)
                        {
                            store.DeleteFile(fileName);
                        }
#endif
                        using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.OpenOrCreate, store))
                        {
                            WriteDTableToStream(stream);
                        }
                    }

 

Writing data to stream is very easy:

 /// <summary>
        /// Write content of a table to a stream
        /// </summary>
        /// <param name="stream">Stream to write table to</param>
        public void WriteDTableToStream(Stream stream)
        {
            string content = string.Empty;
            using (StringWriter stringWriter = new StringWriter())
            {
                XmlSerializer serializer = new XmlSerializer(this.GetType());

                serializer.Serialize(stringWriter, this);
                stringWriter.Flush();
                content = stringWriter.GetStringBuilder().ToString();
                if (!string.IsNullOrEmpty(_password))
                {
                    content = Cryptography.Encrypt(content, _password);
                }
                stringWriter.Close();
            }

            using (StreamWriter writer = new StreamWriter(stream))
            {
                writer.Write(content);
                writer.Flush();
                writer.Close();
            }
        }

The most interesting part of Database class is probably table loading.  This is done via generic function Table<T>:

/// <summary>
        /// FInd instance of a table that contains specific row type
        /// </summary>
        /// <typeparam name="T">Type of object that this table contains</typeparam>
        /// <returns></returns>
        public Table<T> Table<T>()
        {
            ITable returnValue = (from oneTable in Tables
                                  where oneTable.RowType == typeof(T)
                                  select oneTable).FirstOrDefault();
            if (_useLazyLoading && !_loadedTables[typeof(T)])
            {
                Type tableType = typeof(Table<>).MakeGenericType(new Type[] { typeof(T) });
                string fileName = string.Concat(_databaseName, ".", typeof(T).FullName);
                using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    using (IsolatedStorageFileStream tableStream = new IsolatedStorageFileStream(fileName, FileMode.Open, store))
                    {
                        LoadTable(tableStream, tableType);
                        tableStream.Close();
                    }
                }
                _loadedTables[typeof(T)] = true;
                returnValue = (from oneTable in Tables
                               where oneTable.RowType == typeof(T)
                               select oneTable).FirstOrDefault();
            }
            return (Table<T>)returnValue;

        }

 

I would very much appreciate comments and feature requests related to this project.

Thanks in advance for the feedback.

Post to Twitter

Metro Icons for Windows Phone 7

I found this link that will allow you to download set of Metro icons for Windows Phone 7.  You will need to scroll down closer to the bottom of the page to find the actual links.

Enjoy

Post to Twitter

Atlanta .NET Talk on Windows Phone 7

I had a privilege to present on Silverlight development for Windows Phone 7 at local Atlanta.NET Users Group today, March 29th 2010.

You can download PowerPoint presentation here.  Please email me any questions you have regarding the presentation.

Thanks.

Post to Twitter

Windows Phone 7 Application with OData

In this post I will continue exploring Windows Phone 7 development.  Almost any application needs a data source.  There are a few options available for Silverlight applications on Windows Phone.  You can use plain WCF service.  You can optionally put it on Azure.  You can also use Isolated Storage.  Essentially it becomes your custom database.  Of course, you have to write all the API in this case.  Or, you can use OData.  OData approach is the one I am exploring in this post.

First things first, you need to download CTP for OData on Windows Phone.  Here is the link for this download:

http://www.microsoft.com/downloads/details.aspx?FamilyID=b251b247-70ca-4887-bab6-dccdec192f8d&displaylang=en

Download and unzip the files into a folder.  You will need a DLL that is contained in this download – System.Data.Services.Client.Dll

You can follow my previous post and create new Silverlight application for Windows Phone.  There is small change you will need to make.  You need to select the following project template:

image

Now we need to pick an OData source.  I am going to look at www.OData.Org to find one.  I am picking Mix 2010, but you can select any other.  Here is the link I found on OData site – http://api.visitmix.com/OData.svc/

You can always browse the service.  In my case I am going to generate a proxy for this service by running the following command from Microsoft.NET/v4 directory on your local machine:

DataSvcutil.exe /uri:http://api.visitmix.com/OData.svc /DataServiceCollection /Version:2.0 /out:VisitMixClientTypes.cs

DataSvcuil is the .NET utility that generates proxies for ADO.NET Data Services or OData.

Once this is done, copy generated file (VisitMixClientTypes.cs) into the project folder and include it in the project.  What we have inside the file is the proxy for OData service.

Nest step is to update the XAML to match our proxy.  In my simple example I will use the list of sessions and show it on the front page.  Here is what my XAML looks like for my main page (MainPage.xaml)

 

 

<!--ContentGrid contains ListBox. Place additional content here-->
<Grid x:Name="ContentGrid" Grid.Row="1">
    <Grid.Projection>
        <PlaneProjection/>
    </Grid.Projection>
    <ListBox x:Name="ListBoxOne" MouseLeftButtonUp="ListBoxOne_MouseLeftButtonUp"
             Style="{StaticResource PhoneListBox}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel x:Name="DataTemplateStackPanel" Orientation="Horizontal">
                    <Border x:Name="DataTemplateBorder" Height="44" Width="44" BorderBrush="White"
                            BorderThickness="2.5" CornerRadius="100" Margin="10,16,0,0"
                            VerticalAlignment="Top">
                        <Path x:Name="DataTemplatePath" Height="16" Width="11" Fill="White"
                              Stretch="Fill" Margin="4,0,0,0" HorizontalAlignment="Center"
                              VerticalAlignment="Center" UseLayoutRounding="False"
                              Data="M337.59924,129.61948 L337.59924,141.51501 L345.5704,135.87381 z"/>
                    </Border>
                    <mpc:ListViewItem Layout="TextAndDetailsWithIcon" Text="{Binding Title}"
                                      Details="{Binding Body}" Style="{StaticResource PhoneListBoxItemLayout}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

I am only copying the main portion of UI, not entire page here.

I am also going to update the details page that is generated by the project wizard to match my data as well.  Here is what it looks like:

<Grid x:Name="LayoutRoot"
      Background="{StaticResource PhoneBackgroundBrush}"
      d:DataContext="{Binding Items[0]}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <!--TitleGrid is the name of the application and page title-->
    <Grid x:Name="TitleGrid" Grid.Row="0">
        <Grid.Projection>
            <PlaneProjection/>
        </Grid.Projection>
        <TextBlock Text="{Binding Title}" Style="{StaticResource PhoneTextPageTitle2Style}"/>
    </Grid>
    <!--ContentGrid contains the details-->
    <Grid x:Name="ContentGrid" Grid.Row="1">
        <Grid.Projection>
            <PlaneProjection/>
        </Grid.Projection>
        <TextBlock TextWrapping="Wrap" Text="{Binding Body}"
                   Style="{StaticResource PhoneTextBodyTextStyle}"/>
    </Grid>
</Grid>

Now, let’s work on code behind to call our OData service.  Here is entire code behind for MainPage.xaml.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Phone.Controls;
using System.Windows.Navigation;
using EventModel;
using System.Collections.ObjectModel;
using System.Data.Services.Client;
using System.Windows.Input;
namespace WindowsPhoneListApplication1
{
    public partial class MainPage : PhoneApplicationPage
    {
        object _selectedItem;
        EventEntities _entities = new EventEntities(new Uri("http://api.visitmix.com/OData.svc/"));
        public MainPage()
        {
            InitializeComponent();
            SupportedOrientations = SupportedPageOrientation.Portrait;
            Loaded += new RoutedEventHandler(MainPage_Loaded);
            PageTransitionList.Completed += new EventHandler(PageTransitionList_Completed);
            var query = _entities.CreateQuery<Session>("Sessions");
            query.BeginExecute(ar =>
            {
                DataLoaded(ar);
            }, query);
        }
        private void DataLoaded(IAsyncResult result)
        {
            try
            {
                DataServiceQuery<Session> query = result.AsyncState as DataServiceQuery<Session>;
                List<Session> sessions = query.EndExecute(result).ToList();
                Dispatcher.BeginInvoke(() =>
                    {
                        this.ListBoxOne.ItemsSource = sessions;
                    });
            }
            catch (Exception ex)
            {
                Exception thing = ex;
            }
        }
        private void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            // Reset page transition
            ResetPageTransitionList.Begin();
        }
        private void ListBoxOne_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            // Capture selected item data
            _selectedItem = (sender as ListBox).SelectedItem;
            // Start page transition animation
            PageTransitionList.Begin();
        }
        private void PageTransitionList_Completed(object sender, EventArgs e)
        {
            // Set datacontext of details page to selected listbox item
            NavigationService.Navigate(new Uri("/DetailsPage.xaml", UriKind.Relative));
            FrameworkElement root = Application.Current.RootVisual as FrameworkElement;
            root.DataContext = _selectedItem;
        }
    }
}

The code above is fairly easy.  First, I create a DataSericeQuery of type Session.  Session type is part of our generated proxy.  It then call BeginExecute and pass it a handler.  Inside the handler (DataLoaded) I fire EndExecute, then set the items source for my ListBox.  I have to make sure to use Dispatcher for this call, otherwise I will get cross thread access exception because handler is not firing on UI thread.

That is it.  You can now run the application and see the list of sessions at the MIX 2010.  You can also click on an item to see the details.

Please post your questions here.

Thanks.

Post to Twitter

Getting Started with Windows Phone 7 and Silverlight

In this post I will go through the steps of creating my first Windows Phone 7 application using Silverlight.  It will be simple and will mostly concentrate on tools rather than phone specific functionality.  Of course, I will do more posts describing features that are specific to Silverlight for Windows Phone 7.

First thing I have to do is download the tools and install them on my machine.  You can find all appropriate link on www.Silverlight.net.  If you click on Getting Started menu, you can look for phone development tools.  You will download and install Visual Studio 2010 Express for Windows Phone.  Once you are done with that task, start the studio.

Here is what the screen look like.

image

Let’s go ahead and click on New Project link.  Let’s select Silverlight tree node, then Windows Phone application.  One side note – no VB.NET menu inside Studio for Phone.

image

Once project is created, you will see the screen that contains three parts by default – solution explorer, XAML view and Design view.

image

Now we can even run the application.  Let’s go ahead and do this.  What we will see is the Phone emulator as well as studio going to debug mode.  it will take a few minutes first time you run as emulator initializes.  You can resize the emulator by clicking on the menu that I have pointed to with a hand cursor on the picture below.  Eventually application loads, and you will the application just created, more precisely title and subtitle blocks.

image

Let’s add a few controls and some code now.  You will notice that when you stop debugging the studio that emulator keeps running.  This is good, and you want to keep it running in order to save deployment and initialization time. 

We will use the studio’s designer surface to add controls to the surface.  To do so, activate toolbox and pin it.

image

Let’s drag and drop a button onto design surface.  Here is what we will see now.

image

Let’s now add event handler for click event.  To do so, double-click on the button on design surface.  Code view will open and handler will be created.  We will do something really simple, we will change the title as follows:

 

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            this.textBlockPageTitle.Text = "I changed the title";
        }

Let’s run the application and see our code in action by clicking on the button.  Now, the step we are going to do is explore debugging.  To do so, set a breakpoint inside the event handler.

image

Run the application again from studio by clicking on debug button inside the studio.  I put hand cursor next the button.

image

Once the emulator loads the application, click on the new button inside the application we added.  Voila!  Our break    point got hit.

 

I illustrated in this post how to create a sample application inside Express Studio for Windows Phone, add controls to the design surface, write code behind and set breakpoints.

One last note.  You will notice that even new controls dropped onto design surface are styled certain ways to match overall phone design.  If you wonder why, it is because new project wizard comes preloaded with default styles for all basic controls.  To look at those styles, just open app.xaml.  For example, you can search for TargetType="ButtonBase" to see style for button.

There will be more to come as I explore phone specific features in Silverlight for Windows phone.

Thanks.

Post to Twitter