ailon's DevBlog: Development related stuff in my life

Introducing PhoneNameResolver–a lib to decipher Windows Phone models

1/21/2013 8:31:54 PM

image

On Windows Phone you can get information about device’s manufacturer and model using Microsoft.Phone.Info.DeviceStatus class. Unfortunately the results you get do not always represent model names people are used to (see the screenshot above). To make matters worse same models made for different network operators quite often return different values. Additionally returned value quite often changes between batches of the same model. With Windows Phone 8 Nokia went one step further and introduced so many variations of the model name that it became extremely painful to account for all of them manually. That’s why I decided to dedicate a few hours on a weekend to make a small lib that helps with this problem.

PhoneNameResolver (released under MIT license) is a very simple static class that has only one public method called Resolve(). You pass the manufacturer and model name from the DeviceStatus and it returns an object of type CanonicalPhoneName which contains resolved “canonical” (official and/or widely used) model name.

Here’s a sample:

var phone = PhoneNameResolver.Resolve(
    DeviceStatus.DeviceManufacturer, DeviceStatus.DeviceName);
SomeTextBox.Text = phone.FullCanonicalName;

CanonicalManufacturer and CanonicalModel include manufacturer and model separately and are always set. In the case the lib wasn’t able to resolve the model they will be set to the same values passed to the method and IsResolved property will be set to false.

At the moment the lib resolves Nokia, HTC, Samsung and LG model names. The reported/canonical value pairs where collected from public unofficial sources so there’s absolutely no guarantee in the accuracy of the results.

The lib is basically a single C# file and all the model name definitions are included in the same file. I did this to make it extremely easy to just drop the file into your project and to make it work as fast and as config free as possible. That said this is probably not the best architecture to update model definitions without recompiling an app. I’m still open to ideas and this may change in the future. Please let me know your thoughts in the comments below.

Tags: ,

Book Review: Pro WPF in C# 2008: Windows Presentation Foundation with .NET 3.5, Second Edition by Matthew MacDonald

4/29/2009 1:42:00 PM

prowpf After a pretty bland and unexciting ASP.NET book this was a very good change. Matthew MacDonald covers all aspects of WPF in a very good and interesting style. All the basics are covered, principles explained and practical advices are given.

Probably my only but pretty serious complaint is about a Chapter 24 - Custom Elements. This was one of the main chapters (aside from basic WPF principles) why I bought this book in the first place. I was developing our WPF charting controls and expected to find some insights and guidance in this chapter. Unfortunately a big chunk of the chapter (which is not so long to start with) was dedicated to explaining logical implications of building a masked text box. Probably quite interesting stuff on it’s own but not directly related to what it takes to build custom WPF elements in general.

Aside from that I’m very satisfied with this book and can highly recommend it to any .NET/C# developer interested in programming for Windows Presentation Foundation.

Verdict: close to perfect

Buy this book on Amazon.

Tags: , , ,

Add Interactive Flash Charts to Your ASP.NET Web Application. Part 4: Column Chart from Code-behind

8/8/2008 10:29:36 AM

This is the fourth part in the series of tutorials showing how to add dynamic, interactive, data-driven charts to your ASP.NET web applications. These tutorials use amCharts Flash charting components and "ASP.NET Controls for amCharts" for ASP.NET integration.

This part is long overdue. Sorry for that. A tutorial on adding amCharts to ASP.NET page from code-behind was the most requested on amCharts ASP.NET controls forum. So, here we go.

Make sure you have your environment setup, ASP.NET controls for amCharts DLL added and amCharts Column chart added to your project. Details on doing that were provided in Part 1 of the series so I wont repeat it here.

Now let's add a new ASP.NET web form to our project and let's call it CodeBehindBar.aspx. We will only add a single PlaceHolder object to the markup side of our script so it looks like this:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="CodeBehindBar.aspx.cs" Inherits="CodeBehindBar" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <asp:PlaceHolder ID="ChartPlaceHolder" runat="server" />
    </div>
    </form>
</body>
</html>

Now let's switch to the code-behind file.

We will be creating a column chart with two graphs and we'll use Northwind database as data source. The first graph will represent sales totals for 1997 grouped by category and divided by 1000 (just for the sake of being in the same range as our second graph). The second graph will show quantities of products in each group we have in stock.

Make sure that you have access to some SQL Server instance with Northwind database installed, connection string setup, and let's start by pulling our data from SQL Server and placing it into DataSet:

// Get data from Northwind
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString);

SqlCommand myCommand = new SqlCommand("select CategoryName, CategorySales/1000 as CategorySales from [Category Sales for 1997]", conn);
SqlDataAdapter da = new SqlDataAdapter(myCommand);
DataSet ds = new DataSet();
da.Fill(ds, "Category Sales for 1997");

myCommand.CommandText = "select CategoryName, sum(UnitsInStock) as UnitsInStock from [Products by Category] group by CategoryName";
da.Fill(ds, "Products by Category");

conn.Close();

Now it's time to create our chart. We create a ColumnChart object and setup it's DataSource. This is what will be used for the chart series (X axis).

// create column chart
ColumnChart chart = new ColumnChart();
chart.DataSource = ds.Tables["Category Sales for 1997"].DefaultView;
chart.DataSeriesIDField = "CategoryName";
chart.DataSeriesValueField = "CategoryName"; // here it's the same as ID and could've been ommited

Notice that we've specified "CategoryName" as both SeriesIDField and SeriesValueField. This isn't necessary in case like this were we have the same field for both ID and Value. It would suffice to just specify the ID, but I've added Value line so you know you can use different data fields for that.

What we've done so far is created a grid where to add actual data graphs. Now let's create 2 graphs:

// crete sales graph
ColumnChartGraph graph1 = new ColumnChartGraph();
graph1.DataSource = ds.Tables["Category Sales for 1997"].DefaultView;
graph1.DataSeriesItemIDField = "CategoryName";
graph1.DataValueField = "CategorySales";
graph1.Title = "Sales (in thousands)";

// crete stock graph
ColumnChartGraph graph2 = new ColumnChartGraph();
graph2.DataSource = ds.Tables["Products by Category"].DefaultView;
graph2.DataSeriesItemIDField = "CategoryName";
graph2.DataValueField = "UnitsInStock";
graph2.Title = "Units in stock";

and add these graphs to our chart:

chart.Graphs.Add(graph1);
chart.Graphs.Add(graph2);

What's left is just data-binding the chart and adding it to our place holder control on the page

chart.DataBind();
ChartPlaceHolder.Controls.Add(chart);

And that' basically it. This is what you should see if you run this:

 amcharts_code_behind

You can customize the look and feel by changing various properties according to your taste.

Download the source code here: CodeBehindBar.zip (1kb)

kick it on DotNetKicks.com

Tags: , , ,

Accelerated C# 2008 by Trey Nash

6/13/2008 3:56:01 PM

accelerated_csharp_2008I've been developing in C# (on and off) since version 1.0 was in beta. I've read a book about it when version 1 came out and then I relied on online articles, blogs and docs to stay updated. Now (2 versions later) I decided that it's about time to read something systematic on the language to get a complete overview of the things I could've missed over the years and to familiarize myself with new features in C# 3.0 (btw, book title is probably a work of some crazy marketing mind since there's no such thing as C# 2008 AFAIK) .

And the book delivers just what I needed: concise overview of most of the language features complete with samples, usage patterns and best practices. Accelerated C# 2008 (Accelerated) is targeted at developers with some prior experience. It's stated in several places that it's for C++, Java and Visual Basic developers though it's perfectly clear that Trey Nash has lots of things to say to C/C++ and C# guys and not so much to the Java and Visual Basic crowd. Almost all comparisons are done with C++ world so if you are Java/VB developer I suggest you look elsewhere or at least be warned that you wont find many references to these languages.

Verdict: highly recommended for C++ and C# developers, not so much for beginners and Java and VB developers

P.S.: actually in this case I've read a Russian translation of this book titled "C# 2008 ускоренный курс для профессионалов" so I can't talk about publishing related qualities of the book.

Tags: , ,

What's Wrong with this?

5/29/2008 9:55:30 AM

Every time I read a C# book or an article or just a code sample in MSDN I can't stop wondering why don't people (and by people I don't mean just average Joe's but respected authors, MSDN documenters, etc.) use this qualifier unless it's absolutely required to distinguish between identically named local variables and object fields?

I use this all the time and I think it's way easier to understand your own code. And don't get me started on someone else's code. Let me show you an example.

Yesterday I was implementing a SiteMapProvider for a project I'm working on. I looked  at the sample in MSDN. The main "meat" is in BuildSiteMap method. I'll paste it here in full. It's a little long but that's exactly the point.

// Build an in-memory representation from persistent // storage, and return the root node of the site map. public override SiteMapNode BuildSiteMap() { // Since the SiteMap class is static, make sure that it is // not modified while the site map is built. lock (this) { // If there is no initialization, this method is being // called out of order. if (!IsInitialized) { throw new Exception("BuildSiteMap called incorrectly."); } // If there is no root node, then there is no site map. if (null == rootNode) { // Start with a clean slate Clear(); // Select the root node of the site map from Microsoft Access. int rootNodeId = -1; if (accessConnection.State == ConnectionState.Closed) accessConnection.Open(); OleDbCommand rootNodeCommand = new OleDbCommand("SELECT nodeid, url, name FROM SiteMap WHERE parentnodeid IS NULL", accessConnection); OleDbDataReader rootNodeReader = rootNodeCommand.ExecuteReader(); if (rootNodeReader.HasRows) { rootNodeReader.Read(); rootNodeId = rootNodeReader.GetInt32(0); // Create a SiteMapNode that references the current StaticSiteMapProvider. rootNode = new SiteMapNode(this, rootNodeId.ToString(), rootNodeReader.GetString(1), rootNodeReader.GetString(2)); } else return null; rootNodeReader.Close(); // Select the child nodes of the root node. OleDbCommand childNodesCommand = new OleDbCommand("SELECT nodeid, url, name FROM SiteMap WHERE parentnodeid = ?", accessConnection); OleDbParameter rootParam = new OleDbParameter("parentid", OleDbType.Integer);
rootParam.Value = rootNodeId;
childNodesCommand.Parameters.Add(rootParam); OleDbDataReader childNodesReader = childNodesCommand.ExecuteReader(); if (childNodesReader.HasRows) { SiteMapNode childNode = null; while (childNodesReader.Read()) { childNode = new SiteMapNode(this, childNodesReader.GetInt32(0).ToString(), childNodesReader.GetString(1), childNodesReader.GetString(2)); // Use the SiteMapNode AddNode method to add // the SiteMapNode to the ChildNodes collection.

// LOOK HERE
AddNode(childNode, rootNode);
// LOOK HERE

} } childNodesReader.Close(); accessConnection.Close(); } return rootNode; } }

I've highlighted one line in the method:

AddNode(childNode, rootNode);

By glancing at that line could you tell me right away is rootNode a local variable or a field of the object? Wouldn't it be much more obvious if it was

AddNode(childNode, this.rootNode);

We loose readability by omitting this so we must gain something in return, right? What are we gaining? Do I miss something other than saving 5-10 bytes in source file and 5 extra keystrokes? And the keystroke argument isn't always true.

Suppose you have a class defined like this:

class test
{
    public XmlNode XmlNodeHolder;
    public test()
    {
        XmlNodeHolder = null;
    }
}

To type that XmlNodeHolder in the constructor with the help of IntelliSense I had to press 8 keys (x-m-l-n-o-d-e-h) before I got the right line in IntelliSense. Now I would use this

class test
{
    public XmlNode XmlNodeHolder;
    public test()
    {
        this.XmlNodeHolder = null;
    }
}

I could type this.XmlNodeHolder in 4 key presses (t-h-.-x). So the only argument that I see and can't argue with is saving bytes in the file. But who cares about 10 bytes in the source file these days? 100 bytes? 1kb anyone?

So either I miss something important in functionality, performance or something else or I just can't understand the trend.

kick it on DotNetKicks.com

Tags: ,

Property Naming

4/17/2008 4:10:53 PM

I'm implementing support for new features in amCharts 1.5 where you can set Left and Top coordinate of several objects to be measured from opposite side meaning that if you set Left to 20px and specify that this should be actually 20px to the left from the right side of parent object (but it's still a coordinate of the Left corner (not right)). I know it's confusing :)

First I thought I would name new properties Bottom and Right but then I understood that this is not accurate since these are still Top and Left and only the axes change. Now I decided to add 2 boolean properties TopMeasuredFromBottom and LeftMeasuredFromRight but these look quite ugly to me.

Do you have an idea for better naming or/and approach?

Tags: ,

Converting HTML font sizes to pixels

3/7/2008 11:40:12 AM

When you create a custom ASP.NET control most of the times you inherit it from WebControl class or one of it's derivatives. Among other properties WebControl has a Font property of FontInfo type which in turn has a Size property of FontUnit type. Users can set the yourControl.Font.Size to any HTML/CSS compatible value from 12pt to 1.2em to x-large.

This is all fine while your control outputs plain HTML. But at this moment I'm working on a controls which use Flash controls as their output and Flash knows nothing about font sizes in points let alone x-small & co. (at least I was told so by my flash developer colleague). So what I needed was a way to convert all the reasonable FontUnit values to some more or less equivalent pixel sizes. So after some experiments I came up with this FontSizeConverter class with only one static method to convert FontUnit to pixels.

Keep in mind that this is only a raw approximation and doesn't pretend to be completely correct and universal solution. Em and Percentage values use 16px as base.

public class FontSizeConverter
{
    public static int ToPixels(FontUnit unitSize)
    {
        int result = 16;

        if (unitSize.Type != FontSize.NotSet && unitSize.Type != FontSize.AsUnit)
        {
            // size in x-small, etc
            switch (unitSize.Type)
            {
                case FontSize.XXSmall:
                    result = 9;
                    break;
                case FontSize.XSmall:
                    result = 10;
                    break;
                case FontSize.Smaller:
                case FontSize.Small:
                    result = 13;
                    break;
                case FontSize.Medium:
                    result = 16;
                    break;
                case FontSize.Large:
                case FontSize.Larger:
                    result = 18;
                    break;
                case FontSize.XLarge:
                    result = 24;
                    break;
                case FontSize.XXLarge:
                    result = 32;
                    break;
                default:
                    result = 16;
                    break;
            }
        }
        else if (unitSize.Type == FontSize.AsUnit)
        {
            switch (unitSize.Unit.Type)
            {
                case UnitType.Pixel:
                    result = (int)Math.Round(unitSize.Unit.Value);
                    break;
                case UnitType.Point:
                    result = (int)Math.Round(unitSize.Unit.Value*1.33);
                    break;
                case UnitType.Em:
                    result = (int)Math.Round(unitSize.Unit.Value * 16);
                    break;
                case UnitType.Percentage:
                    result = (int)Math.Round(unitSize.Unit.Value * 16 / 100);
                    break;
                default:
                    // other types are not supported. just return the medium
                    result = 16;
                    break;
            }
        }

        return result;
    }
}
kick it on DotNetKicks.com

Tags: , ,

Using Symlinks to Ease Development with Visual Studio Express

11/21/2007 8:01:16 PM

As you probably know, since Visual Web Developer Express and Visual C# Express (or VB for that matter) are separate products and you can't create DLLs in VWD or build web sites in VCS it is painful to develop ASP .NET controls using the Express editions of Visual Studio.

There are several ways to workaround this limitation. Personally I prefer the one where you develop your control in App_Code directory of a test web site in VWD and then when you are ready you copy the .cs files to a project in Visual C# Express and build your DLL(s) from there.

vwd_spaw2

The problem with this approach is that you have 2 copies of your files and as it often happens sometimes you edit the files in one place then in the other dir and you have a mess.

Fortunately this problem can be solved using symbolic links - feature well known to *nix guys and now available in Windows Vista using mklink. As far as I understand you can get the same effect using linkd command in Windows Resource Kit for Windows 2000 and newer but mklink comes with Vista out of the box.

So, what I do is make a symbolic link in my Visual C# project directory which points to a subdirectory in my Visual Web Developer web site:

cmd_mklink

The syntax for mklink in our case is this:

mklink /D new_dir_path original_dir_path

Now we just need to include our newly created "fake" directory into Visual C# Express project and we are all set

vcs_spaw2

This approach can be used in many different scenarios. Currently I work on a couple of related web sites with a colleague. All of the sites originate from one "base" web site. The class files of this base web site are still under development (we update them from time to time). It's too early to compile them and include in our "inherited" web sites as DLLs, so we use the same technique to "include" these common files in our "child" projects.

kick it on DotNetKicks.com

Tags: , , ,

?? operator in C#

11/14/2007 11:24:00 AM

As embarrassing as it sounds I somehow missed the "new" ?? operator and Nullable types (int?, etc.) in C# 2.0. It helps preserve my self-esteem a little that ScottGu thought that this was new in C# 3.0 too. :)

Tags: ,

Copyright © 2003 - 2017 Alan Mendelevich
Powered by BlogEngine.NET 2.5.0.6