Der er sagt og skrevet mange dårlige ting om Microsoft Surface RT.  Jeg har selv haft en RT siden den kom til Danmark, og jeg er ikke enig med den negative kritik, Surface har fået.  Generelt mener jeg, at mange mennesker rakker ned på Microsoft produkter, bare fordi det er moderne.  Jeg går hermed i mod strømmen.

I mine øjne er Surface en tablet computer og dermed en konkurrent til iPad.  Man bør ikke forvente mere af en Surface end af en iPad, og det er måske der, folk misforstår Surface.  Jeg tror ikke, at Surface vil slå iPad.  Men det burde den, og her er 5 (fuldstændig subjektive) grunde til det (i tilfældig rækkefølge):

  1. Split screen.  Idéen med at vise to apps samtidig, med et 1/3 – 2/3 split er genial.  Jeg har f.eks. ofte Skype chat kørende i siden, mens jeg sidder og læser.  Eller f.eks. har jeg Bing Search i siden, mens jeg surfer i Internet Explorer.  Når man klikker på et søgeresultat i Bing Search, vises web siden i IE.  Det kan man ikke engang gøre på en desktop computer!
    Skærmbillede (5)
  2. Touch Cover. Det er virkelig lækkert med et (næsten) full size tastatur, som endda fungerer som cover.  Man skal vænne sig til det, men det er muligt at skrive med næsten fuld hastighed med 10-fingersystem.
  3. Store/små bogstaver på onscreen-keyboard.  På Surface kan man tydeligt se, om man har shift trykket ned, for onscreen-keyboard skifter mellem store og små bogstaver.  Det er en meget lille detalje, men det irriterer mig, at iPad/iPhone ikke gør det.
    Skærmbillede (8)Skærmbillede (7)
  4. Live tiles.  Nogle bliver forvirrede over dem – jeg elsker dem.  Man kan med det samme se, hvem seneste mails er fra, næste kalenderaftale, seneste nyheder, dagens udvikling på C20-indekset, Facebook-opdateringer fra sine søstre, chat-beskeder på Skype osv. osv.  Live tiles er et lækkert alternativ til iPad’s ikoner, der står passive og nærmest skriger til hinanden efter opmærksomhed.
    image
  5. USB-stik.  Det lille USB-stik i siden kombineret med Windows’ væld af drivers gør en verden til forskel.  Sæt dit 5 år gamle Nikon kamera i uden brug af adapter eller noget og overfør (RAW) billederne uden problemer.  Sæt din 4 år gamle Brother laser printer til 800 kr. i og print uden problemer.  Sæt din Windows Phone telefon i og overfør musik og billeder uden problemer.  Jeg har ikke oplevet nogensomhelst problemer med at skulle sætte en disk i A-drevet eller andet, som f.eks. det skete for So Ein Ding.  Alt har virket i første hug for mig.
  6. (ok, jeg løj, der er mere end 5 grunde) Flash.  Det er vel efterhånden kun Danske Spil tilbage, som bruger Flash, men engang imellem er det nyttigt at sidde med en maskine, der kan vise Flash.  Og det kan Surface.
  7. Mini-SD port.  Jeg har endnu ikke haft brug for den, men det er en rar fornemmelse, at den er der.
  8. App-skift med et swipe.  Swipe én gang med venstre tommeltot for at skifte til forrige app.  Swipe en gang ud og ind og se hele listen af kørende apps.  Det er utroligt nemt og intuitivt.
    Skærmbillede (12)
  9. Charms.  Charms er de små ikoner, der kommer frem, når man swiper med højre tommeltot.  Uanset hvilken app, man kører, kan man her finde app’ens indstillinger og muligheder for deling (via Facebook, Skydrive, mail etc).  Det er godt tænkt, fordi det giver konsistens gennem alle apps.  Faktisk er hele konceptet med at bruge tommeltotterne til at styre Surface god.
    Skærmbillede (11)
  10. Flere brugere.  En Surface kan have flere logins.  Slut med at have konens baggrundsbillede af havens pæoner på sin tablet.

Som det måske fremgår, er jeg rigtig glad for Surface.  Det betyder ikke, at den er perfekt.  Jeg håber, at Microsoft en dag kommer med en RT version af Office, så desktoppen helt kan fjernes fra RT.  Der er kommet en udmærket OneNote app, men de andre Office produkter eksekveres på desktoppen, og det er en skam. 

Jeg håber også, at firmaer og udviklere verden over får øjnene op for Surface, så udbuddet af apps bliver større.

Og jeg håber, Microsoft vil gøre noget ved vægten på Surface.  Jeg vil skyde på, at den vejer ca. det samme som en iPad 1.

Det er en god og velkendt tommelfingerregel, at man skal placere et fotografis emne eller “action” 1/3 inde i billedet.  Denne regel er kendt som “Rule of Thirds”.  Det gælder både vertikalt og horisontalt. 

Selvom man ikke kender reglen, vil mange automatisk alligevel bruge den, når de fotograferer, for på en eller anden måde virker det harmonisk for mennesker (og sikkert også for chimpanser, siden vi nu har så meget til fælles med dem).

Digitalkameraproducenter er så flinke at give fotografer mulighed for at få vist guidelines inde i kameraets viewfinder for at hjælpe med at holde kameraet lige etc.  Siden Rule of Thirds er en universiel regel for fotografer, kan jeg simpelthen ikke begribe, hvor de guidelines i mit kamera benytter 4. dele i stedet for 3. dele.  Det ville da gøre livet nemmere.

Sådan ser min viewfinder ud.  Har de brugt en helt ny endnu ukendt regel kaldet Rule of Fourths?

d80_viewfinder_anim.gif

Da async/await pattern blev introduceret med C# 5, blev hele .NET frameworket gennemarbejdet, så relevante asynkrone metoder blev awaitable og fik Task som returværdi.

Det gælder ikke Windows Phone API’en.  Specielt gælder det ikke for WebClient, der i .NET 4.5 bl.a. har fået DownloadDataTaskAsync, der returnerer en Task, og dermed er awaitable.  Til Silverlight må man nøjes med DownloadDataAsync, som er baseret på Event-Based Asynchronous Pattern (EAP) gennem DownloadDataCompleted.

I System.Threading.Tasks namespacet findes en klasse kaldet TaskCompletionSource.  Denne klasse er netop beregnet til EAP scenarier, fordi den opretter en task, som man kan sætte op til at vente på, at en event bliver kaldt.  Dette gøres vha. af SetResult og SetException.  Kalder man en af de to metoder, vil den tilhørende Task afsluttes.  Vha. af TaskCompletionSource har jeg lavet følgende awaitable extension metoder til WebClient, som gør det muligt at lave awaitables for hver af de 4 HTTP metoder GET, POST, PUT og DELETE.  Metoderne benytter JSON via Json.NET:

    public static class WebClientExtensions
    {
        public static Task<T> GetAsync<T>(this WebClient client, Uri uri)
        {
            var tcs = new TaskCompletionSource<T>();
            client.DownloadStringCompleted += (s, e) =>
                {
                    if (e.Error == null)
                    {
                        T result = JsonConvert.DeserializeObject<T>(e.Result);
                        tcs.SetResult(result);
                    }
                    else
                    {
                        tcs.SetException(e.Error);
                    }
                };
            client.DownloadStringAsync(uri);
            return tcs.Task;
        }

        public static Task PostAsync<T>(this WebClient client, Uri uri, T item)
        {
            var tcs = new TaskCompletionSource<string>();
            client.Headers["Content-Type"] = "application/json";
            client.UploadStringCompleted += (s, e) =>
            {
                if (e.Error == null)
                {
                    tcs.SetResult(e.Result);
                }
                else
                {
                    tcs.SetException(e.Error);
                }
            };

            string data = JsonConvert.SerializeObject(item);

            client.UploadStringAsync(uri, "POST", data);
            return tcs.Task;
        }

        public static Task PutAsync<T>(this WebClient client, Uri uri, T item)
        {
            var tcs = new TaskCompletionSource<string>();
            client.Headers["Content-Type"] = "application/json";
            client.UploadStringCompleted += (s, e) =>
            {
                if (e.Error == null)
                {
                    tcs.SetResult(e.Result);
                }
                else
                {
                    tcs.SetException(e.Error);
                }
            };

            string data = JsonConvert.SerializeObject(item);

            client.UploadStringAsync(uri, "PUT", data);
            return tcs.Task;
        }

        public static Task DeleteAsync(this WebClient client, Uri uri)
        {
            var tcs = new TaskCompletionSource<string>();
            client.UploadStringCompleted += (s, e) =>
            {
                if (e.Error == null)
                {
                    tcs.SetResult(e.Result);
                }
                else
                {
                    tcs.SetException(e.Error);
                }
            };

            client.UploadStringAsync(uri, "DELETE", "");
            return tcs.Task;
        }

Du kan læse mere om TaskCompletionSource hos Stephen Toub, som er en af de ypperste, når det kommer til parallelisering i .NET.

Jeg har haft stor glæde af de ovenstående WebClient extensions, men min glæde var endnu større, da jeg fornylig læste, at Microsoft arbejder på en port af HttpClient til Windows Phone, og har gjort det tilgængeligt via NuGet.  Jeg har endnu ikke prøvet det, men det virker lovende.