Here is a simple code sample that show you how you can read the content of a ZIP file:

var localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;

var file = await localFolder.GetFileAsync(“Test.zip”);

var randomStream = await file.OpenReadAsync();

 

using (Stream stream = randomStream.AsStreamForRead())

{

    var zipArchive = new System.IO.Compression.ZipArchive(stream);

 

    // Entries contains all the files in the ZIP

    foreach (var entry in zipArchive.Entries)

    {

        using (var entryStream = entry.Open())

        {

            //

            // Read string file content

            //

            //using (var streamReader = new StreamReader(entryStream))

            //{

            //    var result = await streamReader.ReadToEndAsync();

            //}

 

            //

            // Read string file content (using WinRT APIs)

            //

            using (var inputStream = entryStream.AsInputStream())

            {

                 using (DataReader reader = new DataReader(inputStream))

                 {

                     var fileSize = await reader.LoadAsync((uint)entryStream.Length);

                     var stringContent = reader.ReadString(fileSize);

 

                     // You can also use the other methods available on DataReader to load an IBuffer, Byte Array, etc.

                 }

            }

        }

    }

}

 

Have fun and happy coding!

[Windows 8] How to get a search suggestions list ?

May 15th, 2012 | Posted by Tom in .NET | Article | Windows 8 | WinJS - (0 Comments) | Read: 133

In my Windows 8 application, I’m using the Search contract to allow users to perform searches on the backend web site. But I also wanted to propose some suggestions to the users.

Unfortunately, the APIs exposed by the backend does not offer a way to get some suggestions so I needed to find a way. I started to look on Internet using my favorite search engine and tought: “Hey, I’m trying to implement a feature that is already present in most of the current search engines !”

Screenshot

After some researches, I was unable to find how to get the results proposed by Google (mostly due to the new HTTPS protocol used since few months).

But I wanted to use this feature so I decided to check on YouTube to see if I could get the search suggestions:

Screenshot (2)

Taking a look at under the cover, I discover that, in fact, this suggestions list is just populated after a call to a service:

image

The results of this call is a JSON string containing the suggestions sent by YouTube/Google, according to the query string (“q=YYY”) sent by the user:

image

So, to use the feature, you can just create a simple helper function (results are voluntary restricted to 5 to be used in Windows 8 suggestions list):

function getSuggestions(word) { return new WinJS.Promise(function (complete, error, progress) { var suggestUrl = "http://client1.google.com/complete/search?client=youtube-psuggest&ds=yt&json=t&q=" + word + "&key=" + developerKey; WinJS.xhr({ url: suggestUrl }).then(function (args) { var suggestions = JSON.parse(args.responseText); var results = []; if (suggestions && suggestions.length >= 2) { for (var i = 0; i < 5; i++) { results.push(suggestions[1][i]); } } complete(results); }); }); }

Then, just call your function when user start to enter some text in the Search box:

appModel.Search.SearchPane.getForCurrentView().onsuggestionsrequested = function (eventObject) { var queryText = eventObject.queryText; var suggestions = eventObject.request.searchSuggestionCollection; var deferral = eventObject.request.getDeferral(); // Call services to get search suggestions and add them to the search pane GetSuggestions(queryText).then(function (suggestResults) { suggestResults.forEach(function (item) { if (item) { suggestions.appendQuerySuggestion(item); } }); deferral.complete(); }); };

Even if the results are “limited” to the one proposed by YouTube, the implementation is pretty simple but very useful (at least in my case !)

Screenshot (4)

 

Happy (Windows 8) coding!

In one of his blog post (here or here, for the French version), the Windows 8 Development Master David Catuhe explained how to generate and to rescale a new picture for a tile (secondary or not).

This is very useful if you’re not able to modify the service delivering the images to rescale them automatically. Its technique need you to use an Image HTML element and, unfortunately, you’re not allowed to use graphical components in a Windows 8 background task.

So here is the version I propose, which is quite different. First, I use a Promise when David’s version use an callback parameter. Then, I don’t use an Image element but I take advantage of the BitmapTransform class to perform a transformation (scale, rotation, etc.) on the image, accessed using the BitmapDecoder:

function rescaleImage2(src, destinationWidth, destinationHeight, localfilename) {

    return new WinJS.Promise(function (complete, error, progress) {

        var Imaging = Windows.Graphics.Imaging;

 

        WinJS.xhr({ url: src, responseType: “blob” }).then(function (request) {

            var imageStream = request.response;

 

            var fileName = new Date().getTime() + “_” + parseUri(src).file

 

            Windows.Storage.ApplicationData.current.localFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.replaceExisting).then(function (rootFile) {

                rootFile.openAsync(Windows.Storage.FileAccessMode.readWrite).then(function (stream) {

                    Windows.Storage.Streams.RandomAccessStream.copyAsync(imageStream.msDetachStream(), stream).then(function () {

                        stream.flushAsync().then(function () {

                            stream.close();

                                     Windows.Storage.ApplicationData.current.localFolder.getFileAsync(fileName).then(function(file){

                            file.openReadAsync().then(function (stream) {

                                Imaging.BitmapDecoder.createAsync(stream).then(function (bd) {

                                    var transform = new Windows.Graphics.Imaging.BitmapTransform();

                                    transform.scaledHeight = destinationHeight;

                                    transform.scaledWidth = destinationWidth;

 

                                    bd.getPixelDataAsync(Imaging.BitmapPixelFormat.rgba8, Imaging.BitmapAlphaMode.straight, transform, Imaging.ExifOrientationMode.respectExifOrientation, Imaging.ColorManagementMode.doNotColorManage).then(function (pdp) {

                                        var pixelData = pdp.detachPixelData();

                                       Windows.Storage.ApplicationData.current.localFolder.createFileAsync(localfilename, Windows.Storage.CreationCollisionOption.replaceExisting).then(function (file) {

           file.openAsync(Windows.Storage.FileAccessMode.readWrite).then(function (stream){

                                                                 Imaging.BitmapEncoder.createAsync(Imaging.BitmapEncoder.pngEncoderId, stream).then(function (encoder) {

               encoder.setPixelData(Imaging.BitmapPixelFormat.rgba8, Imaging.BitmapAlphaMode.straight, destinationWidth, destinationHeight, 96, 96, pixelData);

 

               encoder.flushAsync().then(function () {

                   stream.flushAsync().then(function () {

                       stream.close();

                       rootFile.deleteAsync().done(function () {

                           if (complete)

                               complete(“ms-appdata:///local/” + localfilename.replace(“\\”, “/”));

                                                            });

                                                        });

                                                    });

                                                });

                                             });

                                         });

                                      });

                                  });

                              });

                          });

                      });

                  });

              });

          });

      });

    });

}

The code is also available, in a more readable format, here (thanks http://codepaste.net !)

As always, feel free to use it, comment, it, etc.

 

Happy coding!

[Windows 8] Some helpers to use in your developments

May 4th, 2012 | Posted by Tom in .NET | HTML5 | Windows 8 | WinJS - (0 Comments) | Read: 271

Some people ask me if there are some helpers available to perform various tasks such manipulating settings, local storage, etc.

There are no built-in helpers but for the current Windows 8 application I’m working, I’ve developed some of them and I wanted to share them with the community (note that this helpers are available in Javascript but it should not be hard to translate them in C#):

ResourcesHelper:

(function () {

    “use strict”;

 

    var appView = Windows.UI.ViewManagement.ApplicationView;

    var displayProps = Windows.Graphics.Display.DisplayProperties;

    var nav = WinJS.Navigation;

    var ui = WinJS.UI;

    var utils = WinJS.Utilities;

 

    WinJS.Namespace.define(“ResourcesHelper”, {

        ResourcesManager: WinJS.Class.define(

        // Define the constructor function for the ResourcesManager.

            function (resourceFile) {

                this.resourceLoader = null;

 

                if (resourceFile) {

                    this.resourceLoader = new Windows.ApplicationModel.Resources.ResourceLoader(resourceFile);

                }

                else {

                    this.resourceLoader = new Windows.ApplicationModel.Resources.ResourceLoader();

                }

            }, {

                // Instance methods

                ResourceLoader: {

                    get: function () { return this.resourceLoader; }

                },

 

                GetString: function (key) {

                    return this.ResourceLoader.getString(key);

                }

            }, {

                // Static methods               

            }

        )

    });

})();

 

SettingsHelper:

(function () {

    “use strict”;

 

    var applicationData = Windows.Storage.ApplicationData.current;

 

    function hasSetting(key) {

        return new WinJS.Promise(function (complete, error, progress) {

            var result = applicationData.roamingSettings.values.hasKey(key);

 

            complete(result);

        });

    }

 

    function getSetting(key) {

        return new WinJS.Promise(function (complete, error, progress) {

            hasSetting(key).then(function (found) {

                if (found) {

                    var result = applicationData.roamingSettings.values[key];

 

                    complete(result);

                }

                else {

                    complete(false);

                }

            });

        });

    }

 

    function addSetting(key, value) {

        return new WinJS.Promise(function (complete, error, progress) {

            var result = applicationData.roamingSettings.values.insert(key, value);

 

            complete(result);

        });

    }

 

    function removeSetting(key) {

        return new WinJS.Promise(function (complete, error, progress) {

            applicationData.roamingSettings.values.remove(key);

 

            complete();

        });

    }

 

    function updateSetting(key, value) {

        return new WinJS.Promise(function (complete, error, progress) {

            hasSetting(key).then(function (result) {

                if (result) {

                    removeSetting(key).then(function () {

                        addSetting(key, value).then(function (addResult) {

                            complete(addResult);

                        });

                    });

                }

                else {

                    addSetting(key, value).then(function (result) {

                        complete(result);

                    });

                }

            });

        });

    }

 

    function clearSettings() {

        return new WinJS.Promise(function (complete, error, progress) {

            applicationData.roamingSettings.values.clear();

 

            complete();

        });

    }

 

    WinJS.Namespace.define(“SettingsHelper”, {

        HasSetting: hasSetting,

        GetSetting: getSetting,

        AddSetting: addSetting,

        RemoveSetting: removeSetting,

        UpdateSetting: updateSetting,

        ClearSettings: clearSettings

    });

})();

 

StorageHelper:

(function () {

    “use strict”;

 

    var applicationData = Windows.Storage.ApplicationData.current;

    var localFolder = applicationData.localFolder;

 

    function hasSavedContent(file) {

        return new WinJS.Promise(function (complete, error, progress) {

            localFolder.getFileAsync(file).then(function (file) {

                complete(true);

            }, function () {

                complete(false);

            });

        });

    }

 

    function saveToCache(file, content) {

        return new WinJS.Promise(function (complete, error, progress) {

            localFolder.createFileAsync(file, Windows.Storage.CreationCollisionOption.replaceExisting)

                .then(function (file) {

                    file.openAsync(Windows.Storage.FileAccessMode.readWrite).then(function (stream) {

                        var writer = new Windows.Storage.Streams.DataWriter(stream.getOutputStreamAt(0));

                        writer.writeString(content);

                        writer.storeAsync().then(function () {

                            writer.flushAsync().then(function () {

                                complete();

                            });

                        });

                    });

                });

        });

    }

 

    function getFromCache(file) {

        return new WinJS.Promise(function (complete, error, progress) {

            hasSavedContent().then(function (exists) {

                if (exists) {

                    localFolder.getFileAsync(file).then(function (file) {

                        file.openReadAsync().then(function (stream) {

                            var reader = new Windows.Storage.Streams.DataReader(stream.getInputStreamAt(0));

                            reader.loadAsync(stream.size).then(function (fileLength) {

                                var jsonContentAsString = reader.readString(fileLength);

 

                                complete(jsonContentAsString);

                            });

                        });

                    });

                }

                else {

                    complete();

                }

            });

        });

    }

 

    function deleteCache(file) {

        return new WinJS.Promise(function (complete, error, progress) {

            hasSavedContent().then(function (exists) {

                if (exists) {

                    localFolder.getFileAsync(file).then(function (file) {

                        if (file) {

                            file.deleteAsync().then(function () {

                                complete();

                            });

                        }

                        else {

                            complete();

                        }

                    })

                }

                else {

                    complete();

                }

            });

        });

    }

 

    WinJS.Namespace.define(“StorageHelper”, {

        HasSavedContent: hasSavedContent,

        SaveToCache: saveToCache,

        GetFromCache: getFromCache,

        DeleteCache: deleteCache

    });

})();

 

TilesHelper:

(function () {

    “use strict”;

 

    function updateMainTile() {

        return new WinJS.Promise(function (complete, error, progress) {

            complete();

        });

    }

 

    function addSecondTile(tileId, name, image) {

        return new WinJS.Promise(function (complete, error, progress) {

            var tile = new Windows.UI.StartScreen.SecondaryTile(tileId);

            tile.shortName = name;

            tile.displayName = name;

            tile.arguments = tileId;

            tile.tileOptions = Windows.UI.StartScreen.TileOptions.showNameOnWideLogo;

 

            //var uri = parseUri(image);

            //var imageLocalUri = tileId + “_” + uri.file;

 

            var imageLocalUri = tileId + “.jpg”;

 

            rescaleImage2(image, 150, 150, imageLocalUri.replace(“.jpg”, “_uri.jpg”), false).then(function (uriLogo) {

                rescaleImage2(image, 310, 150, imageLocalUri.replace(“.jpg”, “_wide.jpg”), false).then(function (wideLogo) {

                    tile.logo = new Windows.Foundation.Uri(uriLogo);

                    tile.wideLogo = new Windows.Foundation.Uri(wideLogo);

 

                    tile.requestCreateAsync().then(function (isPinned) {

                        if (isPinned) {

                            _updateSecondaryTile(tileId, name, uriLogo, wideLogo);

                        }

 

                        complete(isPinned);

                    });

                });

            });

        });

    }

 

    function updateSecondaryTile(tileId, name, image) {

        return new WinJS.Promise(function (complete, error, progress) {

            isPinned(tileId).then(function (isPinned) {

                if (isPinned) {

                    var tileToUpdate = new Windows.UI.StartScreen.SecondaryTile(tileId);

                    tileToUpdate.shortName = name;

                    tileToUpdate.displayName = name;

                    tileToUpdate.arguments = tileId;

                    tileToUpdate.tileOptions = Windows.UI.StartScreen.TileOptions.showNameOnWideLogo;

 

                    //var uri = parseUri(image);

                    //var imageLocalUri = tileId + “_” + uri.file;

 

                    var imageLocalUri = tileId + “.jpg”;

 

                    rescaleImage2(image, 150, 150, imageLocalUri.replace(“.jpg”, “_uri.jpg”), false).then(function (uriLogo) {

                        rescaleImage2(image, 310, 150, imageLocalUri.replace(“.jpg”, “_wide.jpg”), false).then(function (wideLogo) {

                            tileToUpdate.logo = new Windows.Foundation.Uri(uriLogo);

                            tileToUpdate.wideLogo = new Windows.Foundation.Uri(wideLogo);

 

                            _updateSecondaryTile(tileId, name, uriLogo, wideLogo);

 

                            complete();

                        });

                    });

                }

                else {

                    complete();

                }

            });

        });

    }

 

    function _updateSecondaryTile(tileId, name, uriLogo, wideLogo) {

        // Square tile

        var tileXml = Windows.UI.Notifications.TileUpdateManager.getTemplateContent(Windows.UI.Notifications.TileTemplateType.tileSquarePeekImageAndText04);

        var imageXml = tileXml.getElementsByTagName(“image”);

        imageXml.item(0).attributes.getNamedItem(“src”).innerText = uriLogo;

 

        var textXml = tileXml.getElementsByTagName(“text”);

        textXml.item(0).innerText = name;

 

        // Wide tile

        var wideTileXml = Windows.UI.Notifications.TileUpdateManager.getTemplateContent(Windows.UI.Notifications.TileTemplateType.tileWidePeekImage03);

        imageXml = wideTileXml.getElementsByTagName(“image”);

        imageXml.item(0).attributes.getNamedItem(“src”).innerText = wideLogo;

 

        textXml = wideTileXml.getElementsByTagName(“text”);

        textXml.item(0).innerText = name;

 

        // Merge both xml to get one tile

        var mergedNode = tileXml.importNode(wideTileXml.getElementsByTagName(“binding”).item(0), true);

        tileXml.getElementsByTagName(“visual”).item(0).appendChild(mergedNode);

 

        var notificationUpdater = Windows.UI.Notifications.TileUpdateManager.createTileUpdaterForSecondaryTile(tileId);

        notificationUpdater.clear();

        notificationUpdater.enableNotificationQueue(true);

 

        var tileNotification = Windows.UI.Notifications.TileNotification(tileXml);

        tileNotification.tag = tileId;

 

        notificationUpdater.update(tileNotification);

    }

 

    function removeSecondTile(tileId) {

        return new WinJS.Promise(function (complete, error, progress) {

            isPinned(tileId).then(function (isPinned) {

                if (isPinned) {

                    var tileToDelete = new Windows.UI.StartScreen.SecondaryTile(tileId);

                    tileToDelete.requestDeleteAsync().then(function (isUnPinned) {

                        complete(isUnPinned);

                    });

                }

                else {

                    complete();

                }

            });

        });

    }

 

    function isPinned(tileId) {

        return new WinJS.Promise(function (complete, error, progress) {

            var isPinned = Windows.UI.StartScreen.SecondaryTile.exists(tileId);

 

            complete(isPinned);

        });

    }

 

    function rescaleImage2(src, destinationWidth, destinationHeight, localfilename) {

        return new WinJS.Promise(function (complete, error, progress) {

            var Imaging = Windows.Graphics.Imaging;

 

            WinJS.xhr({ url: src, responseType: “blob” }).then(function (request) {

                var imageStream = request.response;

 

                var fileName = new Date().getTime() + “_” + parseUri(src).file

 

                Windows.Storage.ApplicationData.current.localFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.replaceExisting).then(function (rootFile) {

                         rootFile.openAsync(Windows.Storage.FileAccessMode.readWrite).then(function (stream) {

                             Windows.Storage.Streams.RandomAccessStream.copyAsync(imageStream.msDetachStream(), stream).then(function () {

                                 stream.flushAsync().then(function () {

                                     stream.close();

                                     Windows.Storage.ApplicationData.current.localFolder.getFileAsync(fileName).then(function(file){

                                         file.openReadAsync().then(function (stream) {

                                             Imaging.BitmapDecoder.createAsync(stream).then(function (bd) {

                                                 var transform = new Windows.Graphics.Imaging.BitmapTransform();

                                                 transform.scaledHeight = destinationHeight;

                                                 transform.scaledWidth = destinationWidth;

 

                                                 bd.getPixelDataAsync(Imaging.BitmapPixelFormat.rgba8, Imaging.BitmapAlphaMode.straight, transform, Imaging.ExifOrientationMode.respectExifOrientation, Imaging.ColorManagementMode.doNotColorManage).then(function (pdp) {

                                                     var pixelData = pdp.detachPixelData();

 

                                                     Windows.Storage.ApplicationData.current.localFolder.createFileAsync(localfilename,

                                                         Windows.Storage.CreationCollisionOption.replaceExisting).then(function (file) {

                                                             file.openAsync(Windows.Storage.FileAccessMode.readWrite).then(function (stream) {

                                                                 Imaging.BitmapEncoder.createAsync(Imaging.BitmapEncoder.pngEncoderId, stream).then(function (encoder) {

                                                                     encoder.setPixelData(Imaging.BitmapPixelFormat.rgba8, Imaging.BitmapAlphaMode.straight, destinationWidth, destinationHeight, 96, 96, pixelData);

 

                                                                     encoder.flushAsync().then(function () {

                                                                         stream.flushAsync().then(function () {

                                                                             stream.close();

 

                                                                             rootFile.deleteAsync().done(function () {

                                                                                 if (complete)

                                                                                     complete(“ms-appdata:///local/” + localfilename.replace(“\\”, “/”));

                                                                             });

                                                                         });

                                                                     });

                                                                 });

                                                             });

                                                         });

                                                 });

                                             });

                                         });

                                     });

                                 });

                             });

                         });

                     });

            });

        });

    }

 

    // parseUri 1.2.2

    // (c) Steven Levithan <stevenlevithan.com>

    // MIT License

    function parseUri (str) {

        var    o   = parseUri.options,

        m   = o.parser[o.strictMode ? "strict" : "loose"].exec(str),

        uri = {},

        i   = 14;

 

        while (i–) uri[o.key[i]] = m[i] || “”;

 

        uri[o.q.name] = {};

        uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {

            if ($1) uri[o.q.name][$1] = $2;

        });

 

        return uri;

    }

    parseUri.options = {

        strictMode: false,

        key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],

        q:   {

            name:   “queryKey”,

            parser: /(?:^|&)([^&=]*)=?([^&]*)/g

        },

        parser: {

            strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,

            loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/

        }

    };

 

    WinJS.Namespace.define(“TilesManager”, {

        UpdateMainTile: updateMainTile,

        AddSecondTile: addSecondTile,

        UpdateSecondaryTile: updateSecondaryTile,

        RemoveSecondTile: removeSecondTile,

        IsPinned: isPinned,

        RescaleImage: rescaleImage2

    });

})();

(this last one is probably the one you’ll want to modify a bit, depending to the kind of tile you’ll want to use in your application)

Be aware that there might be some bugs or issues with the code so feel free to let me a comment if you have a fix !

 

Happing coding!

[Windows 8] How to print a document ?

April 16th, 2012 | Posted by Tom in .NET | Article | Windows 8 - (1 Comments) | Read: 217

Here is a simple code sample that can help you if you plan to add the Print feature in your application.

First, you need to setup your application and specify preview pages, options, etc.:

var pd = new PrintDocument();

pd.Paginate += (sender, args) =>

{

    // Set the number of pages to preview

    pd.SetPreviewPageCount(1, PreviewPageCountType.Final);

};

pd.AddPages += (sender, args) =>

{

    // Add a page/document to the print list

    pd.AddPage(this);

    pd.AddPagesComplete();

};

pd.GetPreviewPage += (sender, args) =>

{

    // Indicate the page number to display in the preview window

    pd.SetPreviewPage(args.PageNumber, this);

};

 

var printManager = PrintManager.GetForCurrentView();

printManager.PrintTaskRequested += (sender, args) =>

{

    // Create a print task and set its options

    var printTask = args.Request.CreatePrintTask(“My First WinRT Impression”, requestedArgs => requestedArgs.SetSource(pd.DocumentSource));

    printTask.Options.Orientation = PrintOrientation.Landscape;

};

Finally, you need to display the Print Page to the user:

private async void PrintButtonClick(object sender, RoutedEventArgs e)

{

    // Display the print ui

    await PrintManager.ShowPrintUIAsync();

}

And that’s all!

For your information, if you saved the document as a XPS file, this one is saved in “Documents” library !

 

Happy WinRT coding!

In my day to day job, I have the chance to work on some Windows 8 apps thus, I wanted to share with you some code I’ve found/used and which could be, I hope, useful for you too !

Access files located in installation folder:

const string file = @”Images\Logo.jpg”;

 

var installFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;

var logoFile = await installFolder.GetFileAsync(file);

if(logoFile != null)

{

    //

}

Detect Design Mode:

var isInDesignMode = Windows.ApplicationModel.DesignMode.DesignModeEnabled;

 

Get license information (expiration date, trial mode, etc.):

LicenseInformation licenseInfo = null;

 

#if DEBUG

    // CurrentAppSimulator is use to simulate an object allowing to access to the data

    licenseInfo = Windows.ApplicationModel.Store.CurrentAppSimulator.LicenseInformation;

#else

    licenseInfo = Windows.ApplicationModel.Store.CurrentApp.LicenseInformation;

#endif

    var expirationDate = licenseInfo.ExpirationDate;

    var isTrial = licenseInfo.IsTrial;

Convert HTML text to simple text:

string text = Windows.Data.Html.HtmlUtilities.ConvertToText(

“<div class=\”siteLogo\”><a href=\”/en-us/windows/apps\” title=\”Dev Center -  Metro style apps\”><img src=\”http://i.msdn.microsoft.com/Hash/6b67f1378af22a94e4336f5bfdd136bd.png\” alt=\”Dev Center -  Metro style apps\” title=\”Dev Center -  Metro style apps\” /><span>Dev Center -  Metro style apps</span></a></div>”);

Get all connected devices information:

var deviceWatcher = Windows.Devices.Enumeration.DeviceInformation.CreateWatcher();

deviceWatcher.Added += async (watcher, deviceInformation) =>

{

    var glyphThumbnail = await deviceInformation.GetGlyphThumbnailAsync();

    if(glyphThumbnail.Size > 0)

    {

        // Access to the glyph thumbnail

    }

 

    var thumbnail = await deviceInformation.GetThumbnailAsync();

    if(thumbnail.Size > 0)

    {

        // Access to the thumbnail

    }

};

deviceWatcher.Removed += (watcher, deviceInformation) =>

{};

deviceWatcher.Start();

Detect if keyboard, mouse or touch device is available:

// 1: Present

// 0: Not Present

var isKeyboardPresent = new Windows.Devices.Input.KeyboardCapabilities().KeyboardPresent;

var isMousePresent = new Windows.Devices.Input.MouseCapabilities().MousePresent;

var isTouchPresent = new Windows.Devices.Input.TouchCapabilities().TouchPresent;

Change image used in LockScreen:

var filePicker = new Windows.Storage.Pickers.FileOpenPicker();

filePicker.FileTypeFilter.Add(“.png”);

var selectedFile = await filePicker.PickSingleFileAsync();

 

if(selectedFile != null)

{

    var authPicker = Windows.System.UserProfile.LockScreen.SetImageFileAsync(selectedFile);

}

Get information about connected user (and, optionally, set its pictures):

var userInformation = Windows.System.UserProfile.UserInformation.DisplayName;

Update badge on tile:

var badgeUpdate = Windows.UI.Notifications.BadgeUpdateManager.CreateBadgeUpdaterForApplication();

var template = Windows.UI.Notifications.BadgeUpdateManager.GetTemplateContent(BadgeTemplateType.BadgeNumber);

var textNode = template.SelectSingleNode(“/badge”);

textNode.Attributes[0].NodeValue = “99″;

var badge = new BadgeNotification(template);

 

badgeUpdate.Update(badge);

 

Happy coding!

[Windows 8] How to geolocalize your users ?

April 2nd, 2012 | Posted by Tom in .NET | Windows 8 - (2 Comments) | Read: 263

If you are developing some applications with Windows Phone 7, you may know that it’s possible, for you, to find the position of your users and thus, use it in your application.

Windows 8 now integrate the same concept, thanks to the class Geolocator, which is similar to the GeoCoordinateWatcher class from Windows Phone:

image

So, using this new API is pretty simple:

var geolocator = new Geolocator(); geolocator.PositionChanged += geolocator_PositionChanged; geolocator.GetGeopositionAsync();

Here, I just subscribe to the event PositionChanged and, once this one occurred, I get the position and the coordinates (latitude and longitude):

void geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args) { var position = args.Position; string pos = string.Format("Country:{0} Latitude: {1} Longitude: {2}", position.CivicAddress.Country, position.Coordinate.Latitude, position.Coordinate.Longitude); var action = new Action(() => tb.Text = pos); InvokedHandler handler = (s, ia) => action(); Dispatcher.InvokeAsync(CoreDispatcherPriority.Normal, handler, this, null); }

(Notice the usage of the Dispatcher, to be able to set the Text property of a TextBlock).

So, if you have a service with a method that take in parameters this coordinates, it’s easy for you to display to the user the best results that are near him.

You may wonder how the position is retrieved right ? In fact, Windows will get the information from the GPS that is installed/used. But, as not everybody will have a GPS, the location will be derived from available network information !

To make it possible to work, don’t forget to add the require capacity (location) from the manifest:

image

Now, if you execute your app, Windows will ask user to confirm the use of it’s location:

Screenshot

If user confirm, then the location is displayed correctly:

Screenshot (2)

 

Happy geocoding!

Windows 8 Consumer Preview is available since 2 weeks now and a lot of developers have started to look at how to develop applications using HTML5 / Javascript or XAML / C#.

I’ve got the chance to work with a few customers to help them create their application for Windows 8 Consumer Preview. For one of them, a need was the capacity to show something that could work as a ChildWindow (the one that exists in Silverlight). As nothing is available out of box in WinJS, I created my own control and I would like to share it with the community.

I have to say that I’m not an expert in Javascript so feel free to share your opinions !

Here is the definition of the control:

// For an introduction to the HTML Fragment template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232511
(function () {
    "use strict";

    WinJS.Namespace.define("Controls", {
        ChildWindow: WinJS.Class.define(function (element, options) {
            this._element = element || document.createElement("div");
            var centeredOverlay = this.element;
            centeredOverlay.winControl = this;

            this._overlayBackgroundColor = (options && options.overlayBackgroundColor) ? options.overlayBackgroundColor : "#FFFFFF";
            this._overlayBackgroundOpacity = (options && options.overlayBackgroundOpacity) ? options.overlayBackgroundOpacity : "1";
            this._overlayContainerBackgroundColor = (options && options.overlayContainerBackgroundColor) ? options.overlayContainerBackgroundColor : "white";
            this._rootElement = (options && options.rootElement) ? options.rootElement : document.body;
            this._contentTemplate = (options && options.contentTemplate) ? options.contentTemplate : null;
            this._mustClickOnButtonsToClose = (options && options.mustClickOnButtonsToClose) ? options.mustClickOnButtonsToClose : "true";

            this._initialize(options);
        }, {
            _elementBase: null,
            _elementOverlay: null,

            _element: null,
            _rootElement: null,
            _overlayBackgroundColor: null,
            _overlayBackgroundOpacity: null,
            _overlayContainerBackgroundColor: null,
            _contentTemplate: null,
            _mustClickOnButtonsToClose: null,
            _okButton: null,
            _cancelButton: null,

            element: {
                get: function () {
                    return this._element;
                }
            },

            // Must be in the following format: #RGB or RGB
            overlayBackgroundColor: {
                get: function () {
                    return this._overlayBackgroundColor;
                },
                set: function (data) {
                    this._overlayBackgroundColor = data;
                }
            },

            overlayBackgroundOpacity: {
                get: function () {
                    return this._overlayBackgroundOpacity;
                },
                set: function (data) {
                    this._overlayBackgroundOpacity = data;
                }
            },

            overlayContainerBackgroundColor: {
                get: function () {
                    return this._overlayContainerBackgroundColor;
                },
                set: function (data) {
                    this._overlayContainerBackgroundColor = data;
                }
            },

            rootElement: {
                get: function () {
                    return this._rootElement;
                },
                set: function (data) {
                    this._rootElement = data;
                }
            },

            contentTemplate: {
                get: function () {
                    return this._contentTemplate;
                },
                set: function (data) {
                    this._contentTemplate = data;
                }
            },

            mustClickOnButtonsToClose: {
                get: function () {
                    return this._mustClickOnButtonsToClose;
                },
                set: function (data) {
                    this._mustClickOnButtonsToClose = data;
                }
            },

            _initialize: function (options) {
                var that = this;

                this._elementBase = this._rootElement;

                this._elementOverlay = document.createElement("div");
                this._elementOverlay.id = "elementOverlay";
                //this._elementOverlay.style.zIndex = 99;
                this._elementOverlay.onmousedown = function (eventInfo) {
                    if ((!that.mustClickOnButtonsToClose || that.mustClickOnButtonsToClose == "false") && (eventInfo.srcElement.id == "elementOverlay")) {
                        that.hide();
                    }
                }

                var rootContainer = document.createElement("div");
                rootContainer.style.backgroundColor = this._overlayContainerBackgroundColor;
                rootContainer.style.display = "-ms-grid";
                rootContainer.style.msGridRows = "1fr 50px";
                rootContainer.style.msGridColumnAlign = "center";
                rootContainer.style.msGridRowAlign = "center";

                if (this._contentTemplate) {
                    var templateWidth = this._contentTemplate.style.width ? WinJS.Utilities.convertToPixels(this._contentTemplate, this._contentTemplate.style.width) : WinJS.Utilities.convertToPixels(this._contentTemplate.children[0], this._contentTemplate.children[0].style.width);
                    templateWidth = templateWidth || 250; // default width of 250px

                    rootContainer.style.msGridColumns = templateWidth + "px";

                    rootContainer.appendChild(this._contentTemplate);
                }

                var buttonsPanelDiv = document.createElement("div");
                this._okButton = document.createElement("input");
                this._okButton.type = "button";
                this._okButton.value = "OK";
                this._okButton.style.color = this.overlayContainerBackgroundColor == "white" ? "black" : "white";
                this._okButton.style.borderColor = this.overlayContainerBackgroundColor == "white" ? "black" : "white";

                this._cancelButton = document.createElement("input");
                this._cancelButton.type = "button";
                this._cancelButton.value = "Cancel";
                this._cancelButton.style.marginLeft = "10px";
                this._cancelButton.style.color = this.overlayContainerBackgroundColor == "white" ? "black" : "white";
                this._cancelButton.style.borderColor = this.overlayContainerBackgroundColor == "white" ? "black" : "white";

                buttonsPanelDiv.appendChild(this._okButton);
                buttonsPanelDiv.appendChild(this._cancelButton);

                buttonsPanelDiv.style.msGridColumn = "2";
                buttonsPanelDiv.style.msGridRow = "2";
                buttonsPanelDiv.style.marginRight = "10px";

                rootContainer.appendChild(buttonsPanelDiv);

                this._elementOverlay.appendChild(rootContainer);

                //this._elementBase.parentElement.insertBefore(this._elementOverlay, this._elementBase);
                this._elementBase.appendChild(this._elementOverlay);

                this.hide();
            },

            convertHexToNumber: function (data) {
                if (data.charAt(0) == "#") {
                    data = data.slice(1); //Remove the '#' char - if there is one.
                }

                data = data.toUpperCase();
                var hex_alphabets = "0123456789ABCDEF";
                var value = new Array(3);
                var k = 0;
                var int1, int2;
                for (var i = 0; i < 6; i += 2) {
                    int1 = hex_alphabets.indexOf(data.charAt(i));
                    int2 = hex_alphabets.indexOf(data.charAt(i + 1));
                    value[k] = (int1 * 16) + int2;
                    k++;
                }
                return (value);
            },

            show: function (validationCallBack, cancellationCallBack) {
                var that = this;

                this._okButton.onclick = function () {
                    that.hide();

                    if (validationCallBack) {
                        validationCallBack();
                    }
                };

                this._cancelButton.onclick = function () {
                    that.hide();

                    if (cancellationCallBack) {
                        cancellationCallBack();
                    }
                };

                this._elementOverlay.onkeypress = function (eventObject) {
                    var pressedKeyCode = window.event.keyCode;

                    if (eventObject.key === "Enter") { // User press Enter key
                        that.hide();

                        if (validationCallBack) {
                            validationCallBack();
                        }
                    }
                };

                var height = WinJS.Utilities.getTotalHeight(document.body);
                var width = WinJS.Utilities.getContentWidth(document.body);

                //var templateWidth = this._contentTemplate.style.width ? WinJS.Utilities.convertToPixels(this._contentTemplate, this._contentTemplate.style.width) : WinJS.Utilities.convertToPixels(this._contentTemplate.children[0], this._contentTemplate.children[0].style.width);
                //var templateHeight = this._contentTemplate.style.height ? WinJS.Utilities.convertToPixels(this._contentTemplate, this._contentTemplate.style.height) : WinJS.Utilities.convertToPixels(this._contentTemplate.children[0], this._contentTemplate.children[0].style.height);

                this._elementOverlay.style.height = height + "px";
                this._elementOverlay.style.width = width + "px";
                //this._elementOverlay.style.paddingLeft = ((width / 2) - (templateWidth / 2))+ "px";
                //this._elementOverlay.style.paddingTop = ((height / 2) - (templateHeight / 2))+ "px";
                //this._elementOverlay.style.opacity = this._overlayBackgroundOpacity;
                this._elementOverlay.style.opacity = 1;
                this._elementOverlay.style.backgroundColor = "rgba(" + this.convertHexToNumber(this._overlayBackgroundColor)[0] + ", " + this.convertHexToNumber(this._overlayBackgroundColor)[1] + ", " + this.convertHexToNumber(this._overlayBackgroundColor)[2] + ", " + this._overlayBackgroundOpacity + ")";
                this._elementOverlay.style.msGridColumns = "1fr";
                this._elementOverlay.style.msGridRows = "1fr";
                this._elementOverlay.style.display = "-ms-grid";

                this._contentTemplate.style.display = "inline";
            },

            hide: function () {
                var that = this;

                WinJS.UI.Animation.fadeOut(this._elementOverlay).done(function () {
                    that._elementOverlay.style.opacity = 0;
                    that._contentTemplate.style.display = "none";
                    that._elementOverlay.style.display = "none";
                });
            }
        })
    });
})();

Here are the options available on the control:

  1. overlayBackgroundColor: which define the background color of the ChildWindow
  2. overlayBackgroundOpacity: which define the opacity of the ChildWindow
  3. overlayContainerBackgroundColor: which is used to define the color of the container that will contains the template
  4. rootElement: is the element that will be used to center the ChildWindow
  5. contentTemplate: is the template that will define the content of the ChildWindow
  6. mustClickOnButtonsToClose: is a property that allows you to specify if user must click on the buttons to close the ChildWindow or if the window can be closed if user click anywhere on the screen

To use it, just follow the way you do for all WinJS applications:

<div id="saveSearchTemplate" data-win-control="WinJS.Binding.Template">
        <div style="display: -ms-grid; -ms-grid-rows: 50px 30px 50px; width: 300px; margin-left: 10px;
            margin-top: 15px">
            <h2 style="-ms-grid-row: 1">
                Searh</h2>
            <h4 style="-ms-grid-row: 2">
                Give a name to your search</h4>
            <input id="searchNameValue" style="-ms-grid-row: 3; height: 25px; width: 475px" />
        </div>
    </div>
    <div id="rootElement" class="fragment searchpage">
        <div id="flyout" data-win-control="Controls.CenteredFlyout" data-win-options="{rootElement: select('#flyout'), contentTemplate: select('#saveSearchTemplate'), overlayBackgroundColor: '#898989', overlayBackgroundOpacity: '.3', mustClickOnButtonsToClose: 'true'}">
        </div>
    </div>

As you can see, the content of the ChildWindow is defined using a WinJS Template (to take advantage of the fact that the template are hidden by default).

Hope you’ll like it !

 

Happy coding!

The videos of the sessions I’ve animated during the last TechDays 2012 in Paris, France have been published and are now available:

  1. MVVM de A à Z
  2. WPF 4.5: Quoi de neuf pour les développeurs ?

The last session (“Améliorez votre productivité XAML en entreprise”) has not been published but I’ll update my post as soon as  you’ll be able to see it.

 

Happy coding!

As I’ve explained before, I’ll be presenting 3 sessions during the next TechDays in France.

One of the session is entitled “Améliorer votre productivité XAML en entreprise” and we are currently working on it. If you plan to attend to our session (or to TechDays), we want to learn from you: we give you the opportunity to let us know what you want to see in the session !

If you have any particular needs or if you have some subjects that you want to see covered in the session, let me know (in a comment) and we’ll try do our best !

Thanks and don’t forget: if you plan to come in TechDays 2012, feel free to come to see me.

 

Happy coding!