Overwriting the default WebRequest used by WebClient

by Morten 23. January 2012 21:18

In Silverlight/WPF and WPF there’s today a WebClient class for making webrequests. Under the covers it creates HttpWebRequest for sending the request and HttpWebResponse for handling the response coming back from the server. In an older blogpost, I created a custom WebClient for WP7 that added support for GZIP compression this way.

However the default WebClient doesn’t actually create an “HttpWebRequest/Response” object, since this is an abstract class. What it really does is create internal subclasses that is then used. This is handled by the WebRequestCreator static class which really creates these classes for you. However a less-known feature is that you can actually tell your application that you want to use a specific client for handling the web request and responses for specific domains. You might actually already have fiddled with this in Silverlight if you wanted to explicitly let Silverlight handle the web requests instead of handing it off to the hosting browser control using the following statement:

WebRequest.RegisterPrefix("http://www.mydomain.com/", WebRequestCreator.ClientHttp);

This call makes all requests to www.mydomain.com go through the ClientHttp. As mentioned it’s possible to make your own requestor and completely intercept ANY requests made by WebClient!

If you have your own HttpWebRequest implementation ‘MyHttpWebRequest’, this would look something like this:

public static class MyWebRequestCreator
{
    private static IWebRequestCreate myCreator;

    public static IWebRequestCreate MyHttp
    {
        get
        {
            if (myCreator == null)
            {
                myCreator = new MyHttpRequestCreator();
            }
            return myCreator;
        }
    }

    private class MyHttpRequestCreator : IWebRequestCreate
    {
        public WebRequest Create(Uri uri)
        {
            return new MyHttpWebRequest(uri);
        }
    }
}

So now you can just call:

WebRequest.RegisterPrefix("http://", MyWebRequestCreator.MyHttp);
WebRequest.RegisterPrefix("https://", MyWebRequestCreator.MyHttp);

…and ALL web requests to http or https websites, will be routed through your MyHttpWebRequest class (which you granted still have to build). This class could just wrap the built-in ClientHttpWebRequest and you can modify/add/remove/decode stuff to your pleasing. This is awesome for test framework mock ups, but it’s also really neat for the GZIP WebClient control I mentioned earlier. Why? Well to use my GZipWebClient, you would have to go through all your code and change:

WebClient client = new WebClient();

to

WebClient client = new SharpGIS.WebClient();

This can be a lot of work, and even if you did that, what about all the 3rd party libraries you use, where you can’t go in and change that? Well enter RegisterPrefix! Do you want GZIP support in Hammock? Done! Do you want GZIP support in RestSharp? Done!* Do you want GZIP support in [insert favorite API here]? Done!

*Update: Actually this might not be the case. Some libraries uses some features that either is not possible to implement with the custom HttpWebRequest (like UserAgent), and I didn’t add support for Cookies as well. Both of these are for instance used by RestSharp.

So I went ahead and updated my Nuget Package for the GZipWebClient, so go grab v1.1, and you will only have to add 1-2 LINES OF CODE, and just execute it ONCE (for instance at startup), and EVERYTHING WebClient will be enhanced with GZIP compression. You can also grab the updated source on the original blogpost here.

I really have to give some credit to my co-worker Anargyros for this one, who mentioned that it might be possible to do it this way. Go follow him on twitter and give him some twitter love @tomahawk1187

Tags:

Windows Phone | WPF | Silverlight

Why Silverlight 5’s 3D is (almost) useless

by Morten 10. December 2011 12:49

So Silverlight 5 finally hit the web this week, and there’s a lot of cool new features – some of which I’m very excited about, but probably the biggest feature ever added - the 3D XNA API that allows you to render directly to the graphics card using the new DrawingSurface API - I’m not so excited about any more. Why? Because between the RC and RTM release this feature has been heavily crippled. Here’s an excerpt from the recent blogpost describing the change:

[…] you may experience security errors with Silverlight 5 RTM when you want to use the wonderful new 3D feature. In fact, some graphics drivers may allow malicious code to execute. That may lead to an unwanted hard reset or a blue screen.

Starting with the beta version, to protect users for this kind of trouble, we initiate a first scenario where all Windows XP Display Driver Model (XPDM) drivers on Windows XP, Windows Vista, and Windows 7 will be blocked by default. Permission will be granted automatically in elevated trust scenarios and Windows Display Driver Model (WDDM) drivers will not require user consent at run-time.

But as always, features, including security features, continue to be refined and added during post-beta development.

And for the RTM version, there were a number of approaches considered to further improve security and stability, but the solution to block 3D in partial trust by default was the best option for this release. Permission is still granted automatically in elevated trust scenarios.

So already during beta and RC, we had a security limitation that certain old type of display drivers would disable this mode, unless you ran in full trust. Considering the uptake on WDDM, I didn’t consider this limitation a big problem. After all technology moves forward, and old tech sometimes needs to be left behind. After all one of the reasons for moving to the WDDM model was to stabilize the system.

Post RC this limitation was increased to be across all systems and display drivers. I was lucky enough to get a heads up about this a little over two months ago, but I feel truly sorry for the people who had been betting on this feature and are ready to release their 3D apps now that RTM has hit. The communication of this limitation shouldn’t have stayed within a small group of people under NDA, but should have been communicated out to the community. It probably didn’t happen because it could probably have fueled the “Silverlight is dead” fire (and rightfully so). I would have like to have seen a more open discussion of this, similar to what the Windows 8 team has on their “Building Windows 8” blog. In June the Silverlight Team had promised that the DoS issue that beta and RC had, would be mitigated and developers were counting on this feature.

So I’m not saying that security shouldn’t take precedence, but I would have like to see a more focused effort to either improve the experience – either by dedicating a lot of resources to weed out the security issues, delay the release, or at the very least make it easier for users to opt in. – perhaps communicating that this is a temporary limitation and will be resolved in a GDR update. Considering the late change, I get that the Silverlight team didn’t have much time to turn around and improve this experience. However, there’s already a feature like this for when you want to use the webcam that works much better. When I in Silverlight want to use the webcam, I ask the user for permission, and I’m met with the following dialog:

image

It’s pretty easy and it’s clear to the user what he/she needs to do. I wish we had gotten a similar dialog for enabling 3D. Instead, now in Silverlight, all you can do is detect that the 3D capability is blocked and try and describe to the user what to do. These are the steps you would have to guide them through:

  • Right click on your Silverlight plugin.
  • Click the “Silverlight” option.
  • Go to the permissions tab.
  • Find the domain that hosts the .xap file (which might not be obvious since it could be different than where the website is located).
  • When you find the entry (and this list could be quite long), you have to click “Allow” – no indication here what that really means for the casual PC user (how do you use a blocked display driver?!??).

image

Was this really the best experience we could have gotten? It’s actually easier to ask the user to install the app in full trust (which is an even unsafer mode), than the above experience. I’m sure Average Joe would not like this experience, have trouble finding this out, and probably even be scared to death to do anything he’s not used to doing (I know my parents wouldn’t ever get through this). So all you are going to see on your website is a plugin container that just sits there unused, and not getting to show how awesome this thing could really have been.

It’s such a shame, because this API can vastly improve rendering performance in many scenarios, and opens up an entirely new group of 3D based web based apps. And it would have worked across a wide range of browsers (more so than WebGL at this point).

The 3D capabilities are still great for out-of-browser apps and internal line-of-business apps where it’s a lot easier to deploy an app in full trust (especially with SL5’s new in-browser full trust feature). But are that really the type of apps where you expect to be using the 3D feature a lot?

Tags:

Silverlight

WinRT vs. Silverlight - Part 8 - What other people are blogging

by Morten 6. December 2011 18:27

See intro blogpost here.

Over the last few months several other people have been writing blog posts covering the transition from WPF/Silverlight/WP7 to WinRT. Below are some of the ones I’ve stumbled upon.

Colin Eberhardt - XAMLFinance - A Cross-platform WPF, Silverlight and WP7 Application
An app that reuses code across 3 different XAML platforms and compiles for all of them. A great example that this can be accomplished. Also make sure to check out Colin’s blog for more WinRT goodness.

Jeffrey Richter - Core .NET Type usable from a Metro Styl Application
A list of the “standard” .NET types that are available in WinRT as well.

Andy’s blog - Physics Games: Multi-targeting Windows 8 and Windows Phone 7
Andy goes through building a physics-based game for both Windows 8 and Windows Phone 7. Also check out his Physics Helper library for WinRT.

Tim Greenfield - “WinRT Genome Project”
Visual comparison of how much overlay Silverlight 5 and WinRT has.

Tim Greenfield - Silverlight 5 vs. WinRT comparison
A follow-up to the link above with a comparison of namespaces, members, types and differences between SL5 and WinRT. This is an amazing list if you want to get into the details when reusing code between the two frameworks.

Pontus Wittenmarks’s - 10 tips about porting Silverlight apps to WinRT/Metro style apps (Part 1)
A quick list of of tips when porting from Silverlight to WinRT.

Petzold Book Blog - Windows 8 Dependency Property Strangeness
Talks about some of the issues with Dependency Properties in Windows 8. I already briefly touched on this, but this goes a lot more in-depth.

If I find more, I’ll add them here, or feel free to mention any other good resources in the comments below.

Tags:

Windows Runtime | WPF vs Silverlight | Windows Phone | WPF | Silverlight

Correctly displaying your current location

by Morten 20. November 2011 19:23

With GPS receivers integrated in phones, tablets and PCs, a lot of apps are being built that displays your current location. Usually the GPS API’s that these devices come with provides you with two values: Longitude and Latitude in decimal degrees, and often an estimated accuracy in meters. Most apps just display these values as is, without considering formatting or number of significant digits. This blog post attempts to show how this could be done. I’ll use C# for this, but it should apply to any device, language and API out there.

Formatting

Some people think of longitude as the “X” in an ordinary flat X,Y the coordinate system and latitude as Y/Up/North. It’s technically not correct because this is not a flat coordinate system, but a ‘polar’ coordinate system - I do however understand this simplification and I think of it the same way internally when working with code that deals with any type of coordinate system. However, how things work internally and how they are displayed are two very different things. An example of this are date objects: They are usually stored and handled as a ‘tick’ number, but we never display it like that. Geographical coordinates are the same way. They have one way they are stored in memory, and a completely different way to be displayed.

First of all lets get the order out of the way: If you still think of longitude as the ‘x’ you probably want to display this value first. However it’s commonly agreed upon that latitude is displayed before longitude.

Next are negative coordinates. Instead of showing a latitude/longitude as for instance -117,34 you would write 117°W 34°N. So we prefix the coordinate with N/S and E/W depending on weather the coordinate is positive or negative. So in C# this could look like this:

char ns = lat < 0 ? 'S' : 'N'; //Southern or Northern hemisphere?
char ew = lon < 0 ? 'W' : 'E'; //Eastern or Western hemisphere?
string formatted = string.Format("{0}°{1} , {2}°{3}", Math.Abs(lat), ns, Math.Abs(lon), ew);

Now this is still decimal degrees. A more ‘proper’ format would be to use the degrees, minutes, seconds (DMS) format . Some people do prefer decimal degrees though, so you might want to make this a configurable option. But if you expect people to be using this coordinate to plot a position on a map, you are better off using DMS, since this is the format maps uses along its edge - and it also looks prettier. Degrees are denoted with a °, minutes with a single quote ' and seconds with a double quote ". For example 117°W 23' 12.34”

To make this conversion you will first show the integer part of the degrees. Take the remainder multiply by 60, and you’ll get the minutes. Lastly take the remainder of that and do the same, and you got the seconds (and you can display the seconds with decimals, but see the part on ‘accuracy’ next).  Below is what that will look like in C#:

char ns = lat < 0 ? 'S' : 'N'; //Southern or Northern hemisphere?
char ew = lon < 0 ? 'W' : 'E'; //Eastern or Western hemisphere?
//Make positive
lon = Math.Abs(lon);
lat = Math.Abs(lat);
//Grab the part in front of the decimal
var majorLong = Math.Floor(lon);
var majorLat = Math.Floor(lat);
//the value after the decimal in minutes (*60)
var minorLong = (lon - majorLong) * 60;
var minorLat = (lat - majorLat) * 60;
//Minutes:
var minutesLong = Math.Floor(minorLong);
var minutesLat = Math.Floor(minorLat);
//Seconds:
var secondsLong = (minorLong - minutesLong) * 60;
var secondsLat = (minorLat - minutesLat) * 60;
string formatted = string.Format("{0}{1}°{2}'{3}\" {4}{5}°{6}'{7}\"", ns, majorLat, minutesLat, secondsLat, ew, majorLong, minutesLong, secondsLong);

Accuracy

Often I see a location displayed as for example -117.342817243 , 34.212381313. When I see this many digits I instantly think ‘oooooh that’s a very accurate location’. But this is very misleading. In college, several of our professors would fail our reports if the end result displayed more digits than the accuracy of the input data. The same thing applies here. If your GPS receivers accuracy is 1000m, how many digits should you display, and how many meters is one second?

First a little about the size and shape of earth: While earth is not a perfect sphere, it’s fairly close to an ellipsoid (this is still an approximation though). It’s widest at equator, and smallest (flattened) between the north and south pole. So in ellipsoid-speak the parameters are:

Semi-major axis: 6,378,137m
Semi-minor axis: 6,356,752.3142m
Mean radius (mR): 6,367,449m

So back to the question: How many meters is one second? This is pretty easy to determine for latitude, but unfortunately this is not a straightforward conversion for longitude, since this changes with the latitude. Let’s first start with the simpler latitude:
First we need the circumference of Earth along a meridian (a line that goes north/south) and Equator:

Circumference at Equator: 2 * Pi * 6,378,137 = 40,075,016 m
Circumference of a meridian : 2 * Pi *  6,356,752 = 39,940,652 m

For simplicity let's stick with a rough average of 40mio meters, since this is not going to really matter for the end result.
From that we get:

Horizontal length of one degree at Equator or along a meridian:
     40,000,000 / 360 = 111,111m
Horizontal length of one second at Equator or along a meridian:
    111111.111 / 60 minutes / 60 seconds = 31m

So from that we get that we should never display any decimals on seconds unless our accuracy is better than 31 meters. And we shouldn’t display more than one decimal unless the accuracy is 3m or better (which never happens with standard GPS equipment). Similarly if we are using decimal degrees instead of DMS for display, how much does the n'th digit matter at Equator or along a meridian?

5 digits: 0.000,01 * 40000000 = 400m 
6 digits: 0.000,001 * 40000000 = 40m
7 digits: 0.000,000,1 * 40000000 = 4m

So in this case we will only show 7 digits if accuracy is better than 40m, and probably never more than 7 digits.

Latitude always goes along a meridian, so the number of significant digits doesn't ever change with your location. But the length of one degree at a longitude changes with the latitude you're at.
The radius of a longitude at a given latitude is: cos(latitude)*mR*2*PI.
At 34 north or south that would be: 33,168,021m. So here the number is roughly 3m instead of 4m, meaning you are more likely to show more digits on the longitude portion for the coordinate, the further north you go. In general practice however, this is not going to matter too much, since it only gets better. so to keep it simple we’ll just stick with the same conversion at all latitudes.

Bringing it all together

So let’s bring all this together into a C# ValueConverter you can use for binding against a GeoCoordinate object returned by the GeoCoordinateWatcher in .NET and Windows Phone. A converter parameter is used for choosing whether you want DMS or decimal degrees as output.

using System;
using System.Device.Location;
using System.Globalization;
using System.Windows.Data;

namespace CoordinateDisplay
{
    /// <summary>
    /// Converts a GeoCoordinate to Degrees-Minutes-Seconds
    /// </summary>
    public class CoordinateConverter : IValueConverter
    {
        private const double MeanEarthRadius = 6367449; //meters
        private const double MeanEarthCircumference = 2 * Math.PI * MeanEarthRadius; //meters
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is GeoCoordinate)
            {
                var coord = value as GeoCoordinate;
                if(coord.IsUnknown) return "Unknown";

                double lat = coord.Latitude;
                double lon = coord.Longitude;
                if ((parameter is string) &&
                    string.Compare("decimal", parameter as string, StringComparison.OrdinalIgnoreCase) == 0)
                //show as decimal degrees
                {
                    var decimalsLat = 7;
                    var decimalsLon = 7;
                    int val = 4;
                    if (coord.HorizontalAccuracy > val * 100) decimalsLat = 5;
                    else if (coord.HorizontalAccuracy > val * 10) decimalsLat = 6;
                    val = (int)Math.Floor(Math.Cos(lat / 180 * Math.PI) * MeanEarthCircumference / 10000000d);
                    if (coord.HorizontalAccuracy > val * 100) decimalsLon = 5;
                    else if (coord.HorizontalAccuracy > val * 10) decimalsLon = 6;
                    return string.Format("{0}°,{1}°", Math.Round(lat, decimalsLat), Math.Round(lon, decimalsLon));
                }
                else //Show as degrees/minutes/seconds
                {
                    char ns = lat < 0 ? 'S' : 'N'; //Southern or Northern hemisphere?
                    char ew = lon < 0 ? 'W' : 'E'; //Eastern or Western hemisphere?
                    //Make positive
                    lon = Math.Abs(lon);
                    lat = Math.Abs(lat);
                    //Grab the part in front of the decimal
                    var majorLong = Math.Floor(lon);
                    var majorLat = Math.Floor(lat);
                    //the value after the decimal in minutes (*60)
                    var minorLong = (lon - majorLong) * 60;
                    var minorLat = (lat - majorLat) * 60;
                    //Seconds:
                    var minutesLong = Math.Floor(minorLong);
                    var minutesLat = Math.Floor(minorLat);

                    //one digit accuracy on one second equals ~3m or better
                    //this changes with the latitude, but this is good enough for now
                    int decimals = 1;
                    if (coord.HorizontalAccuracy > 30)
                        decimals = 0; //With this accuracy we don't need to show sub-second accuracy
                    //Seconds:
                    var secondsLong = Math.Round((minorLong - minutesLong) * 60, decimals);
                    var secondsLat = Math.Round((minorLat - minutesLat) * 60, decimals);
                    return string.Format("{0}{1}°{2}'{3}\" {4}{5}°{6}'{7}\"",
                        ns, majorLat, minutesLat, secondsLat,
                        ew, majorLong, minutesLong, secondsLong);
                }
            }
            return value;
        }

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

Here’s an example of using that in XAML where the datacontext is the GeoCoordinate:

<Grid>
    <Grid.Resources>
        <local:CoordinateConverter x:Name="dmsConverter" />
    </Grid.Resources>
    <StackPanel>
        <TextBlock Text="Degrees minutes seconds:" />
        <TextBlock Text="{Binding Converter={StaticResource dmsConverter}}" />
        <TextBlock Text="Decimal degrees:" />
        <TextBlock Text="{Binding Converter={StaticResource dmsConverter}, ConverterParameter=decimal}" />
        <TextBlock Text="{Binding Path=HorizontalAccuracy, StringFormat=Accuracy: \{0:0\}m}" />
    </StackPanel>
</Grid>

And what this can look like on a Windows Phone with different accuracies (notice the different number of digits):

imageimage

You can download this sample app here.

Tags:

Silverlight | WPF | Windows Phone | Windows Runtime

WinRT vs. Silverlight - Part 7 - Making WebRequests

by Morten 5. October 2011 13:35

See intro blogpost here.

In Silverlight and WPF you are probably used to using WebClient to perform downloads. This is a simple class for doing download/upload string or retrieving a response stream from the server. However, in Windows Runtime this client doesn’t exists. Instead we have new a simple “HttpClient” to do much of what WebClient can. However it works very differently by using the new Task framework, and the more you dive into porting code to WinRT, you will see this a lot, and it will make your life porting code cumbersome. On the upside, the Tasks framework is awesome and it’ll often simplify you code a great deal! I talked a bit about this in my previous post, so please read that first, before you continue here, since this will be building on top of that.

Let’s say we have a method in WPF and Silverlight that uses WebClient to downloada and create an image. Since this is working asynchronously, we would have to either use event handlers or action delegates to return the result and/or the error. The method could look something like this:

public void GetContent(Uri uri, Action<string> complete, Action<Exception> error)
{
    WebClient client = new WebClient();
    client.DownloadStringCompleted += (sender, e) =>
    {
        if (e.Error != null)
            error(e.Error);
        else {
            complete(e.Result);
        }
    };
    client.DownloadStringAsync(uri);
}

 

Here’s how a method like that could look in WinRT:

public async Task<string> GetContentI(Uri uri)
{
   System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
   var result = await client.GetAsync(uri);
   return result.Content.ReadAsString();
}

Simple right? Well it' gets even simpler when we have to start consuming that method.

From SL and WPF you would consume the method something like this:

GetContent(uri, (text) => {
          TextBlock tb = new TextBlock() { Source = text };
          LayoutRoot.Children.Add(tb);
      },
      (error) => { /*TODO: handle error*/ }
);

And the same using the Task framework:

try {
   TextBlock tb = new TextBlock() { Source = await GetContent(uri) };
   LayoutRoot.Children.Add(tb);
catch { /*TODO: handle error */ }

You tell me what’s more elegant and readable? Smile

My point here is that Tasks are awesome, so rather than trying to reuse your existing code in WinRT, consider rewriting your existing code to use Tasks and it will work much smoother.

There’s lets create a method for downloading a string over the network that works the same way across the board. (I’ll assume you are using the Async Task CTP for Silverlight or WPF for this).

public async Task<string> GetContent(Uri uri)
{
#if WINRT
    System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
    var reqResult = await client.GetAsync(uri);
    return reqResult.Content.ReadAsString();
#else
    WebClient client = new WebClient();
    TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
    client.DownloadStringCompleted += (sender, e) =>
    {
        if (e.Error != null)
            tcs.TrySetException(e.Error);
        else
            tcs.TrySetResult(e.Result);
    };
    client.DownloadStringAsync(uri);
    return await tcs.Task;
#endif
}

Note you could also use the new .NET method “WebClient.DownloadStringTaskAsync” which would simplify the above quite a lot. I used the event based approach to demonstrate how you would handle the cases where you don’t already have a task implementation available.

Tags:

WPF vs Silverlight | Windows Runtime | WPF | Silverlight

WinRT vs. Silverlight - Part 6 - Using Tasks

by Morten 5. October 2011 09:54

See intro blogpost here.

When you start working with WinRT, you start seeing classes missing or changed. A lot of methods are now only asynchronous, like making a web request, opening, reading and writing files etc. They all now on the Task framework, and they do this to ensure you application is always responsive. However without this framework, it would be a pain to code against an API that’s inherently asynchronous all the way through. But with it, it makes it really easy to write code against it.

As an example here’s how you normally write async operations in WPF and Silverlight:

var myObject = new MyClass();
myObject.Completed += (sender,e) => { 
   //Completed event handler 
if(e.Error == null) { statusText.Text = "My Operation has completed: " + e.Result;
} }; myObject.StartAsync(); //Starts process and fires "Completed" event when done

So we first hook up to the event handler, then call start. When you look at the code, the lines are not executed in the order they are written. The completed delegate executes after the operation completes after Start() has been run (even explaining it makes it sound confusing). Also you cannot throw exceptions from an asynchronous running process, because there will be no way to catch it, so you’ll have to parse an exception object back as part of your result and check it.

This pattern makes it hard to read and understand the code, since it’s not immediately obvious what code runs when. Especially when the code gets more complex and/or your eventhandlers are declared elsewhere. When we then nest events, it gets very convoluted quickly:

var myObject = new MyClass();
myObject.Completed += (sender,e) => { 
   if(e.Error == null) {
       //Perform next operation
       var myObject2 = new MyClass();
       myObject2.Completed += (sender2,e2) => { 
           if(e2.Error == null) {
              //Completed event handler
              statusText.Text = "My Operation has completed: " + e2.Result;
} }; myObject2.StartAsync(); } }; myObject.StartAsync();

With the Task framework this becomes very simple and straightforward to write and more importantly read:

var myObject = new MyClass();
try {
     string result = await myObject.StartAsync();
     var myObject2 = new MyClass();
     string result2 = await myObject2.StartAsync();
     statusText.Text = "My Operation has completed: " + result2;
} catch { }

Notice that we don’t bother with checking an error object. We simply use try/catch instead, and the task returns the result up front. If it wasn’t for the little “await” keyword, it looks like this is just good ol’ synchronous programming! This is pure awesomeness!

If you are planning on porting a large application from Silverlight or WPF and it uses a lot of event-based asynchronous programming, you are probably in for some work. Not to say that your application can’t use events, but a lot of the WinRT API’s don’t have eventhandlers any more, so if you insist on keeping it this way, you would have to wrap all the built in tasks into some event-based classes. I would probably rather focus on moving forward and getting this cleaned up. And since the Task framework is already available in .NET 4 and there’s a CTP for Silverlight (and included in upcoming v5!) and WinPhone, you could port your original code to start taking advantage of this, making your code reuse easier and cleaner moving forward.

So how would you go about wrapping an event-based class into a task based method? Well let’s continue using the MyClass example above, and wrap it in a task. Here’s how that would look:

public Task<string> StartAsync()
{
    var tcs = new TaskCompletionSource<string>();
    var obj = new MyClass();
    obj.Completed += (sender,e) => {
        if (e.Error != null)
              tcs.TrySetException(e.Error);
        else
              tcs.TrySetResult(e.Result);
    };
    obj.StartAsync();
    return tcs.Task;
}

Basically we return Task of string, instead of just a string. We use the TaskCompletionSource of string to handle error and result messaging back to the task.

So when should you make a method an asynchronous task? The rule of thumb is: If it takes more than 50ms to execute, it should be asynchronous! This helps a lot towards preventing the UI from becoming choppy and/or unresponsive.

Tags:

Silverlight | Windows Runtime | WPF

WinRT vs. Silverlight - Part 5 - Defining default style template

by Morten 17. September 2011 19:38

See intro blogpost here.

Here's something that's actually NOT different in Silverlight (but it's different from WPF as it has always been).
You declare your style using DefaultStyleKey. This means the code looks like this for Silverlight, WPF and Windows Runtime:

public class MyControl : Control
{
    public MyControl()
    {
#if SILVERLIGHT || WINRT
        this.DefaultStyleKey = typeof(MyControl);
#endif
    }
    static MyControl() {
#if !SILVERLIGHT && !WINRT
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(HoverControl),
            new FrameworkPropertyMetadata(
            typeof(HoverControl))); 
#endif
    }
}

Here is what IS different though: You need to set the build action of \Themes\Generic.xaml to "Content". It won't work without it.
Also note that when you add Generic.xaml to your project, it will also get added to App.Xaml. I assume this is a bug in the current release, but you will have to go and delete this entry, or it won't work.

Tags:

Windows Runtime | WPF vs Silverlight | WPF | Silverlight

WinRT vs. Silverlight - Part 4 - Dispatcher

by Morten 16. September 2011 11:01

See intro blogpost here.

In Silverlight and WPF you will often use the Dispatcher to return from a background thread to jump to the UI Thread. This is required when you need to update your UI, because you’re not allowed to touch the UI from anything but the UI Thread. The Dispatcher method has changed slightly in WinRT. It’s also now of type “CoreDispatcher”, instead of just “Dispatcher”.

#if !WINRT
  Dispatcher.BeginInvoke(
#else
  Dispatcher.Invoke(CoreDispatcherPriority.Normal, 
#endif
           (s, a) => { ... }
#if WINRT
      , this, null);
#endif
   );

Tags:

Windows Runtime | Windows Phone | WPF vs Silverlight | WPF | Silverlight

WinRT vs. Silverlight - Part 3 - Dependency Properties

by Morten 16. September 2011 08:55

See intro blogpost here.

Declaration of dependency properties has changed in the WinRT. This is a temporary change and will go away when WinRT hits beta, but still good to know if you start prototyping on WinRT today. If you are a control developer this is probably one of the things you would have to change in the most places.

Here’s what the API looks like for Silverlight and WPF for registering a Dependency Property or an Attached Property:

public static DependencyProperty Register(
      string name, 
      Type propertyType, 
      Type ownerType,
      PropertyMetadata typeMetadata);
public static DependencyProperty RegisterAttached(
      string name, 
      Type propertyType,
      Type ownerType, 
      PropertyMetadata defaultMetadata);

And here’s what this currently looks like in WinRT CTP :

public static DependencyProperty Register(
      string name, 
      string propertyTypeName, 
      string ownerTypeName,
      PropertyMetadata typeMetadata);
public static DependencyProperty RegisterAttached(
      string name, 
      string propertyTypeName,
      string ownerTypeName, 
      PropertyMetadata defaultMetadata);

Notice how the PropertyType and PropertyOwnerType is now strings instead of types!

This means you would have to write your code like this to make it cross-compile:

        public double MyDoubleProperty
        {
            get { return (double)GetValue(MyDoublePropertyProperty); }
            set { SetValue(MyDoublePropertyProperty, value); }
        }

        public static readonly DependencyProperty MyDoublePropertyProperty =
            DependencyProperty.Register("MyDoubleProperty", 
#if WINRT
             "Double", "MyNamespace.MyControl", 
#else
                typeof(double), typeof(MyNamespace.MyControl), 
#endif
                 new PropertyMetadata(0d));

Also note that you don’t use the full type name for the system types. Ie. here you use “Double” and not “double” or “System.Double”.

You could create a few static methods to replace the Register/RegisterAttached methods that will make your code cross-platform, and switch it out just there when this changes. Here’s one example how this could be accomplished (the ‘ToRTString’ method isn’t fully tested though…):

    public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType, PropertyMetadata metadata)
    {
        return DependencyProperty.RegisterAttached(name, 
#if WINRT
            propertyType.ToRTString(), ownerType.ToRTString()
#else
            propertyType, ownerType
#endif
            , metadata);
    }
    public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata metadata)
    {
        return DependencyProperty.Register(name,
#if WINRT
            propertyType.ToRTString(), ownerType.ToRTString()
#else
            propertyType, ownerType
#endif
            , metadata);
    }
#if WINRT
    private static string ToRTString(this Type type)
    {
        string name = type.FullName;
        if(name.StartsWith("System."))
            return name.Substring(7);
        else
            return name;
    }
#endif

Tags:

Windows Runtime | WPF | WPF vs Silverlight | Silverlight

WinRT vs. Silverlight - Part 2 - Code Namespace

by Morten 16. September 2011 08:15

See intro blogpost here.

The namespaces in WinRT has changed for all the UI related classes. Generally System.Windows has been replaced with Windows.UI.Xaml, and the rest is the same below that. If we were to declare a “WINRT” compiler directive, the typical default using statements that would compile on both Silverlight, WPF and WinRT would look like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
#if !WINRT
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Documents;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Xaml.Shapes;
#endif

This is also described in greater detail here: http://msdn.microsoft.com/en-us/library/windows/apps/hh465136(v=VS.85).aspx

Tags:

Windows Runtime | WPF vs Silverlight | WPF | Silverlight

About the author

Morten Nielsen

Silverlight MVP

Morten Nielsen
<--That's me
E-mail me Send mail

Twitter @dotMorten 

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2005-2011

Month List

RecentComments

Comment RSS