Using database in Windows Phone app

Database in windows phone app is using LINQ to SQL, a .NET component that provide infrastructure for managing relational data as objects (reference). Creating and manipulating the database require a few steps from defining the data structure to querying the database

For this example, we have a database named School with one table Student

Student
- id <int> (PK)
- name <string>
- biography <string>
- registered <datetime>
- major <StudentMajor>

StudentMajor (enumerable)
- Engineering
- Medical
- Computer Science

First, define the table and enum class above. ‘ID’ is primary key, autoincrement field. ‘Biography’ field wont be checked for consistency when doing update operation. ‘Major’ contains enumerable value

[Table]
public class Student
{
    private int id;
    [Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
    public int ID
    {
        get { return id; }
        set { id = value; }
    }

    private string name;
    [Column(DbType = "NVARCHAR(255)")]
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    private string biography;
    [Column(DbType = "NText", UpdateCheck=UpdateCheck.Never)]
    public string Biography
    {
        get { return biography; }
        set { biography = value; }
    }

    private DateTime registered;
    [Column]
    public DateTime Registered
    {
        get { return registered; }
        set { registered = value; }
    }

    private StudentMajor major;
    [Column]
    public StudentMajor Major
    {
        get { return major; }
        set { major = value; }
    }
}

public enum StudentMajor
{
    Engineering,
    Medical,
    ComputerScience
}

Next, define a database by extending DataContext class and override its base constructor

public class SchoolContext : DataContext
{
    public static string ConnectionString = "Data Source=isostore:/School.sdf";
    public Table<Student> Students;
    public SchoolContext(string connectionString) : base(connectionString) { }
}

Now, we can open the database and do some query on it.

SchoolContext db = new SchoolContext(SchoolContext.ConnectionString);

To query for student with ID 100

var result = from Student s in db.Students
             where s.ID == 100
             select s;
Student student = result.FirstOrDefault(); // return null if not found

To query for students enroll in Engineering major

var result = from Student s in db.Students
             where s.Major == StudentMajor.Engineering
             select s;
Student[] students = result.ToArray();

Note: for insert, update or delete operation, you need to call SubmitChanges() to save the changes to the database. Also note that you need to wrap SubmitChanges() in try catch block, to catch any possible error raised when saving the changes.

To insert new student record. (reference)

db.Students.InsertOnSubmit(new Student()
{
    Name = "John Doe",
    Biography = "Description about this student",
    Registered = DateTime.UtcNow,
    Major = StudentMajor.Medical
});
db.SubmitChanges();

To update a student record (reference)

var result = from Student s in db.Students
             where s.ID == 100
             select s;
Student student = result.FirstOrDefault();
if (student != null)
{
    student.Name = "James Bond";
    db.SubmitChanges();
}

To delete a student record (reference), for example student with ID 90

var result = from Student s in db.Students
             where s.ID == 100
             select s;
Student student = result.FirstOrDefault();
if (student != null)
{
    db.Students.DeleteOnSubmit(student);
    db.SubmitChanges();
}

To delete bulk record of students, for example student enrolled in ComputerScience major

var result = from Student s in db.Students
             where s.Major == StudentMajor.ComputerScience
             select s;
db.Students.DeleteAllOnSubmit(result.ToList());
db.SubmitChanges();

Create event based component in C#

This post is about how to create event based component in C# for Windows Phone. Assuming that we have XAML class that interact with data model component, we’re using event to pass the data around.

In model class, create delegate and event property. Delegate is property that define the signature of callback, and event is property that other class can hook their callback to.

If you want to pass additional parameters in event handler, declare a new event argument class that extend EventArgs and assign the values when raising the event

public class DataLoadedEventArgs : EventArgs
{
	public int TotalRows { get; set; }
}

public class DataSource
{
	public delegate void DataLoadedEventHandler(object sender, DataLoadedEventArgs e);
	public delegate void DataErrorEventHandler(object sender, EventArgs e);

	public event DataLoadedEventHandler DataLoaded;
	public event DataErrorEventHandler DataError;

	public void GetDataFromServer()
	{
		// code for getting data

		// this is how to raise the event
		if (DataLoaded != null)
		{
			DataLoaded(this, new DataLoadedEventArgs()
			{
				TotalRows = 20
			});
		}

		// if has error, raise another event
		if (DataError != null)
		{
			DataError(this, new EventArgs());
		}
	}
}

Then in XAML class attach the callback to listen for the event raised from the model class, and make sure to detach the event when not used anymore.

public partial class MainPage : PhoneApplicationPage
{
	private DataSource dataSource;

	private void MainPage_Loaded(object sender, RoutedEventArgs e)
	{
		dataSource = new DataSource();
		dataSource.DataLoaded += dataSource_DataLoaded;
		dataSource.DataError += dataSource_DataError;
	}

	private void MainPage_Unloaded(object sender, RoutedEventArgs e)
	{
		dataSource.DataLoaded -= dataSource_DataLoaded;
		dataSource.DataError -= dataSource_DataError;
	}

	private void dataSource_DataLoaded(object sender, DataLoadedEventArgs e)
	{
		// use e.TotalRows
	}

	private void dataSource_DataError(object sender, EventArgs e)
	{
		// ...
	}
}

Load JSON data from web in Windows Phone

This post is about how to load JSON data from web server using HttpWebRequest in C# for Windows Phone application. Let’s say we have URL as follows:

http://api.domain.com/student?id=1

Which output JSON data with format:

Student
- id <int>
- name <string>
- cgpa <float>

First, declare the data contract, based on the JSON response format above.

using System.Runtime.Serialization
namespace MyApp
{
    [DataContract]
    public class Student
    {
        [DataMember]
        public int id { get; set; }

        [DataMember]
        public String name { get; set; }

        [DataMember]
        public float cgpa { get; set; }
    }
}

Then, create a http request using HttpWebRequest. It is discouraged to use WebClient because it is running synchronously, compared to HttpWebRequest, which is running asynchronously.

Using RequestState object is encouraged because during response callback, we are using this object to get the original http request, which can help prevent concurrency issues if this function is called simultaneously from different part of our program

In the http request asynchronous callback, we’ll parse the JSON string into C# objects, using DataContractJsonSerializer. 

using System.Net;
using System.Runtime.Serialization.Json;

// this is our request state class. should be declared within a namespace,
// but being simplified here for demo purposes
public class RequestState
{
    public HttpWebRequest Request { get; set; }
}

// method to request for data from web server. this should be within a class
public void GetData()
{
    String url = "http://api.domain.com/student?id=1";
    HttpWebRequest request = HttpWebRequest.CreateHttp(url);
    try
    {
        RequestState state = new RequestState()
        {
            Request = request
        };
        request.BeginGetResponse(request_BeginGetResponse, state);
    }
    catch (Exception e)
    {
        // error when sending http request
    }
}

// callback method that will be invoked asynchronously when
// http response finish being received
private void request_BeginGetResponse(IAsyncResult ar)
{
    try
    {
        RequestState state = (RequestState)ar.AsyncState;
        using (WebResponse response = state.Request.EndGetResponse(ar))
        {
            using (Stream stream = response.GetResponseStream())
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Student));
                Student student = (Student)serializer.ReadObject(stream);
                // handle received data here
            }
        }
    }
    catch
    {
        // exception when reading http response
    }
}

Merge XAML and code-behind file in Visual Studio

When you’re importing Windows Phone view file (XAML + its class file) into a project, it’s shown in Visual Studio as separate files. Compared to when you’re creating a new view file, its class file (code-behind) is grouped behind the XAML file.

To ‘merge’ these two files, you need to edit the project settings file (*.csproj file)

<Compile Include="MainPage.xaml.cs"/>

to

<Compile Include="MainPage.xaml.cs">
    <DependentUpon>MainPage.xaml</DependentUpon>
</Compile>

Reference: http://stackoverflow.com/questions/18121494/how-to-merge-a-xaml-file-and-its-code-behind-with-visual-studio

DataContractJsonSerializer missing assembly reference

DataContractJsonSerializer class is declared under System.Runtime.Serialization assembly. Even when the assembly is already added to project reference, it’s still complaining about missing assembly.

It’s actually included in System.Servicemodel.Web assembly. Include it to your Windows Phone project reference will solve the error.

Windows Phone app dev note

wpbuildtarget
Build target:

  • Windows Phone OS 7.1 – can run on WP7.5 to WP8 devices
  • Windows Phone OS 8 – can run on WP8 devices only

Visual Studio 2010 supports Windows Phone OS 7.1 (Silverlight 4)
Visual Studio 2012 supports Windows Phone OS 7.1 & 8 (Silverlight 5)

Compatibility:

  • If build target is WP OS 7.1, can only use API from SDK 7.1, can’t use new API from SDK 8 even when compile with the latest SDK. Either to use WP7Toolkit or reflection method to be able to access SDK 8 API
  • If build target is WP OS 7.1, only support WVGA screen resolution only, and only WP OS 7.1 tile
  • If build target is WP OS 8, can only run on WP8 devices – so, to to support more WP devices, need to compile 2 xap files for both build target

App Icons

  • Windows Phone OS 7.1 = 62 x 62 PNG
  • Windows Phone OS 8 = 99 x 99 PNG

Tile Icons

  • Windows Phone OS 7.1 = 173 x 173 PNG
  • Windows Phone OS 8 (Ref. about tile sizes & templates)
    • 3 sizes – small (app list), medium & wide (start screen)
    • 3 templates – flip, cycle & iconic
  • Small
    • flip & cycle: 159 x 159
    • iconic: 110 x 110
  • Medium
    • flip & cycle: 336 x 336
    • iconic: 202 x 202
  • Wide
    • flip & cycle: 691 x 336

App image for windows phone store = 300 x 300 non-transparent png

Splash images.

Windows Phone OS 7.1

  • WVGA = 480 x 800 – SplashScreenImage.jpg

Windows Phone OS 8

  • WVGA = 480 x 800 – SplashScreenImage.Screen-WVGA.jpg
  • WXGA = 768 x 1280 – SplashScreenImage.Screen-WXGA.jpg
  • 720p = 720 x 1280 – SplashScreenImage.Screen-720p.jpg

Notes

  • If compiled with target Windows Phone OS 7.1, it only support WVGA screen resolution, when displayed on 720p, will have extra padding on top of the app