Tuesday, 31 July 2012

Creating a Windows 8 Metro App Package

The following procedure shows how to create a Windows 8 Metro App Package. The next article will be the more complicated procedure to install it!

1. With your solution open in VS2012 or 2011, Pick Store->Create App Package... from the toolbar menu:


2. A dialogue box will appear asking if you want to upload it to the store, I've selected no because it's just for testing:


3. Click Next and another dialogue will appear with the packaging options. It let's you change things like version and build configuration:


4. Click 'Create' and the package will be created. Easy:


Monday, 11 June 2012

Windows 8 Metro MVVM Light Push Notification Fix

I'm working on a WP7 port to Windows 8 and got to the push notifications section. I'd been struggling to get notifications to work. Mike Taulty kindly helped me out with this: http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2012/06/08/windows-8-metro-style-app-simple-wns-push-notification.aspx to test notifications without Azure. My MVVM Light app wouldn't respond and I was getting 403 - Forbidden responses from the WNS server. I suspected there may be something wrong with my app so I built a bog standard "Hello Windows 8" app which worked nicely, so it proved that there was something wrong with my app!


I figures it would be something wrong with an ID or something similar because I know in WP7 MVVM Light projects the app GUID in the manifest is always the same which causes apps to be overwritten on deployment. There is no ID in the manifest so I had a look at the pfx file and it's got Laurent's id on it. So this is what I did:


1. Copied the pfx from "Hello Windows 8" app to my MVVM Light app and renamed it.


2. Edited the MVVMLightProject.csproj and changed the name and thumbprint of the pfx to that of "Hello Windows 8"



    <DefaultLanguage>en-US</DefaultLanguage>
    <FileAlignment>512</FileAlignment>
    <ProjectTypeGuids>{BC8A1FFA-BEE3-4634-8014-XXXXXXXXXX};{FAE04EC0-301F-11D3-BF4B-XXXXXXXXXX}</ProjectTypeGuids>
    <PackageCertificateKeyFile>XXXX_TemporaryKey.pfx</PackageCertificateKeyFile>
    <PackageCertificateThumbprint>E31B6A298677237928A520954AF2FXXXXXXXXXX</PackageCertificateThumbprint>
    <ExpressionBlendVersion>5.0.30129.0</ExpressionBlendVersion>
  </PropertyGroup>


3. Launched my app and grabbed the channel URI from the output window (noticed it was slightly longer than before) and put it into Mike's app along with the other API info and....


4. It worked!

Tuesday, 15 May 2012

Windows 8 Metro - GridView ItemClick Command Attached Property

Windows 8 Metro doesn't support triggers, so it's not easy to bind commands to events in the view any more. This is an attached property which can be attached to a GridView to bind a command to the ItemClick event:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;


namespace AAWP.Commanding
{
    public class GridViewItemClickCommand
    {
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(GridViewItemClickCommand), new PropertyMetadata(null, CommandPropertyChanged));


        public static void SetCommand(DependencyObject attached, ICommand value)
        {
            attached.SetValue(CommandProperty, value);
        }


        public static ICommand GetCommand(DependencyObject attached)
        {
            return (ICommand)attached.GetValue(CommandProperty);
        }


        private static void CommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            // Attach click handler
            (d as GridView).ItemClick += gridView_ItemClick;
        } 


        private static void gridView_ItemClick(object sender, ItemClickEventArgs e)
        {
            // Get GridView
            var gridView = (sender as GridView);


            // Get command
            ICommand command = GetCommand(gridView);


            // Execute command
            command.Execute(e.ClickedItem);
        }
    }
}

Usage:

<GridView
                x:Name="itemGridView"
                AutomationProperties.AutomationId="ItemGridView"
                AutomationProperties.Name="Grouped Items"
                Margin="116,0,40,46"
                ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
                ItemTemplate="{StaticResource Standard250x250ItemTemplate}"
                SelectionMode="None"
                IsItemClickEnabled="True"
                cmd:GridViewItemClickCommand.Command="{Binding ItemClickCommand}" >

Monday, 16 April 2012

ScrollViewer AutoScroll Behavior

Overview
This behavior causes a ScrollViewer to automatically scroll to the bottom when it's contents change size. It is useful for TextBox controls inside ScrollViewers so that the cursor doesn't disappear whilst typing.


The Behavior


    public class AutoScrollBehavior : Behavior<ScrollViewer>
    {
        private ScrollViewer _scrollViewer = null;
        private double _height = 0.0d;

        protected override void OnAttached()
        {
            base.OnAttached();

            this._scrollViewer = base.AssociatedObject;
            this._scrollViewer.LayoutUpdated += new EventHandler(_scrollViewer_LayoutUpdated);
        }

        private void _scrollViewer_LayoutUpdated(object sender, EventArgs e)
        {
            if (this._scrollViewer.ExtentHeight != _height)
            {
                this._scrollViewer.ScrollToVerticalOffset(this._scrollViewer.ExtentHeight);
                this._height = this._scrollViewer.ExtentHeight;
            }
        }     

        protected override void OnDetaching()
        {
            base.OnDetaching();

            if (this._scrollViewer != null)
                this._scrollViewer.LayoutUpdated -= new EventHandler(_scrollViewer_LayoutUpdated);
        }
    }

Implementation in XAML

<ScrollViewer Height="200">
    <i:Interaction.Behaviors>
        <cmd:AutoScrollBehavior />
    </i:Interaction.Behaviors>
    <TextBox IsEnabled="{Binding Path= IsCommentEnabled}" Text="{Binding Path=Comment, Mode=TwoWay}" MinHeight="200"
        AcceptsReturn="True" InputScope="Text" TextWrapping="Wrap">
    </TextBox>
/ScrollViewer>

Thursday, 12 April 2012

MVVM Light - Passing Params to Target ViewModel Before Navigating - Part II

After a lot more thinking about this, I've come up with a really neat solution, needs more testing, but here it is in current form. There's a MessageSender and MessageReceiver class which between them handle sending InitMessageBase type objects and allow buffering and requesting of a message if target is not constructed.


Example code here


Part 1 here


MessageSender


    public class MessageSender<T> where T : InitMessageBase
    {
        private T _message = default(T);

        public MessageSender()
        {
            // Send back item when a constructor asks for it
            Messenger.Default.Register<T>(this, message =>
            {
                if (this._message != null && this._message != message && !this._message.Received)
                {                     
                    // Send back original message
                    Messenger.Default.Send(this._message);
                }
            });
        }

        public void SendMessage(T message)
        {
            // Store value
            this._message = message;

            // Try and send message
            Messenger.Default.Send(message);
        }
    }

MessageReceiver

    public class MessageReceiver<T> where T : InitMessageBase
    {
        private Action<T> _handler = null;
        private T _message = null;

        public MessageReceiver(Action<T> handler)
        {
            this._handler = handler;

            // Wait for messages
            Messenger.Default.Register<T>(this, message =>
            {
                if (this._message != null && this._message != message && !message.Received)
                {
                    message.Received = true;

                    this.OnMessageReceived(message);
                }
            });
        }

        /// <summary>
        /// Send empty message on instantiation
        /// </summary>
        /// <param name="message"></param>
        public MessageReceiver(Action<T> handler, bool sendInitMessage)
            : this(handler)
        {
            if (sendInitMessage)
            {
                this._message = Activator.CreateInstance(typeof(T)) as T;

                // Send empty message
                Messenger.Default.Send<T>(this._message);
            }
        }

        private void OnMessageReceived(T message)
        {
            if (this._handler != null)
                this._handler( message );
        }
    }

InitMessageBase

    public abstract class InitMessageBase : MessageBase
    {
        // Used for a send
        public bool Received { get; set; }

        public InitMessageBase()
        {

        }
    }

An Implementation of InitMessageBase

    public class ArticleInitMessage : InitMessageBase
    {
        public  Article Value { get; set; }

        public ExampleInitMessage()
        {

        }

        public ExampleInitMessage( Article value)
        {
          this.Value = value;
        }
    }

Sending a Message
Simply create a global instance of the MessageSender and send a message or value:

if (this._articleSender == null)
this._articleSender = new MessageSender<ArticleInitMessage>();

this._articleSender.SendMessage(new ArticleInitMessage(article));

this._navService.NavigateTo(ViewModelLocator.ArticleUri);

Receiving a Message
Simply create a global instance of MessageReceiver at VM construct time and pass it an action to do:

this._articleReceiver = new MessageReceiver<ArticleInitMessage>((message) =>
{
this.SelectedItem = message.Value;
}, true);






Thursday, 5 April 2012

MVVM Light - Passing Params to Target ViewModel Before Navigating

Overview
I use MVVM Light for my WP7 apps, it's great! I implement the following navigation service for controlling navigation from the view model layer:


http://blog.galasoft.ch/archive/2011/01/06/navigation-in-a-wp7-application-with-mvvm-light.aspx


Part 2 Here


The main problem I've faced is that I often want to pass parameters to the target view's view model to prepare it for what it needs to do. It is possible to access properties in the target view model through the ViewModelLocator as each view model has a static property used for the view binding via the non-static properties, however this means that the view models are tightly coupled through the VML and it seems like a bit of a hack.


The example code is from an article page which requires navigation to a links page.


Messaging
It's possible to fire a message out before navigating to pass parameters to the target view model, however, if the target view has never been hit, the associated vm will not not have instantiated so will not receive the message! This can be worked around by calling the VML CreateXXX method however this is still not the elegant solution I was hoping for.


2-Way Messaging
To solve this problem, I figured that when a VM instantiates, ask if any other VM has any parameters for it then register a message pipe for parameters when it is instantiated.

The Message
I created a message which would take a parameter to pass from the source to the target or an action to request a parameter from the source, by the target:


public class LinksInitMessage : MessageBase
{
    public Article Payload { get; set; }
    public Action<Article> Callback { get; set; }

    public LinksInitMessage(Article payload)
    {
        this.Payload = payload;
    }

    public LinksInitMessage(Action<Article> callback)
    {
        this.Callback = callback;
    }
}


Source VM
First off messages need registering (at constructor stage) so that the target VM may message back one it constructs:


private void RegisterMessenger()
{
    //Register any messages
    Messenger.Default.Register<LinksInitMessage>(this, msg =>
    {
        if (this._linksInitItem != null)
        {
            msg.Callback(this._linksInitItem);
            this._linksInitItem = null;
        }
    });
}

Then when the source VM is ready to navigate , it can send out a message and keep a parameter in case the VM calls back, then navigate:

private void Link()
{
    // Send message to Links (it will get it if it's there otherwise, the VM will request when open)
    Messenger.Default.Send<LinksInitMessage>(new LinksInitMessage(this._selectedItem));

    // Store article incase Links requests it
    this._linksInitItem = this._selectedItem;

    // Nav to links
    _navService.NavigateTo(ViewModelLocator.LinksUri);
} 


Target VM
First off when the VM constructs, it sends out a message to ask if any other VM has any a message for it, if it gets a response it can initialise itself. Second it registers a message type so once it is already instantiated, it can receive params again and re-initialise itself:

private void RegisterMessenger()
{
    //Send out a message to see if another VM has params we need
    Messenger.Default.Send<LinksInitMessage>(new LinksInitMessage(article =>
    {
        if (article != null)
        {
            this.SelectedItem = article;
        }
    }));

    //Register any message pipes
    Messenger.Default.Register<LinksInitMessage>(this, msg =>
    {
        this.ClearViewModel();
        this.SelectedItem = msg.Payload;
    });
}

Conclusion
That's it, seems like a nice loosely coupled way of initialising a view model on navigation.


Thursday, 19 January 2012

WP7 HTTP Using Sockets & Problem With HttpWebRequest

Why Would You Want To Do This?
The first question you will have unless you found this article because you know what the problem is already is: why would you want to use sockets when there is a perfectly good way of sending and receiving data using WebClient and HttpWebRequest objects? Well the problem explains it.

The Problem
I recently had to integrate a WP7 Mango app with the Disqus API. I set out thinking it would be fairly straight forward, but as soon as I started work on it I ran into a big problem. I was using HttpWebRequests to do a simple HTTP GET, here's the code:

private void button1_Click(object sender, RoutedEventArgs e)
        {
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(new Uri("http://disqus.com/api/3.0/threads/listPosts.json?forum=abcd&thread:ident=12345&api_key=abcdef0123456789"));
            req.BeginGetResponse(EndGetResponse, req);
        }

        private void EndGetResponse(IAsyncResult a)
        {
            try
            {
                HttpWebRequest req = a.AsyncState as HttpWebRequest;
                HttpWebResponse res = req.EndGetResponse(a) as HttpWebResponse;

                Stream s = res.GetResponseStream();
                StreamReader str = new StreamReader(s);
                string data = str.ReadToEnd();
            }
            catch (Exception ex)
            {
                string s = ex.ToString();
            }
        }

Normally this should work fine, but an exception was being thrown at EndGetResponse:

System.Net.WebException: The remote server returned an error: NotFound. ---> 

Now this exception is not very helpful so you need to use a protocol analyser (I use WireShark, I gave up with Fiddler because I never got it working with the phone!) to find out what the problem is. It turns out that it's 400 Bad Response code:


Now if you profile a browser making the same request you notice some differences:


For some reason (I don't know what) WP7 (.Net doesn't do this) adds a "Referer" header with a reference to some location on the device. The API server doen't like this and rejects the request. This is the problem.

Possible Solutions
One obvious solution would be to remove the offending header, but this is not possible. Another solution would be to change the "Referer" header value, this is possible but doesn't work. After some thought I realised that since HTTP is only a layer on top of TCP and since MS have kindly given us Sockets to use in the Mango update that Sockets are the solution.

Sockets
First job is to get a new client to handle asynchronous TCP requests, there's a nice MS example for a Tic-Tac-Toe game (Noughts and Crosses if you're from the UK!). This is the example download link: http://go.microsoft.com/fwlink/?LinkId=219075

The AsynchronousSocketClient is the bit we're interested in, but it needs some adjustment because we need the socket to keep receiving data until there is no more. I changed the ProcessReceive method to this:

// Called when a ReceiveAsync operation completes  
        private void ProcessReceive(SocketAsyncEventArgs e)
        {
            Socket sock = e.UserToken as Socket;

            if (e.SocketError == SocketError.Success)
            {
                // Received data from server 
                dataFromServer += Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
                
                // More data to receive
                if (e.BytesTransferred > 0)
                {
                    //Read data sent from the server 
                    sock.ReceiveAsync(e);
                }
                else
                {
                    sock.Shutdown(SocketShutdown.Both);
                    sock.Close();
                    sock.Dispose();

                    ResponseReceivedEventArgs args = new ResponseReceivedEventArgs();
                    args.response = dataFromServer;
                    OnResponseReceived(args);
                }
            }
            else
            {
                if (retries < MAX_RETRIES)
                {
                    retries++;

                    try
                    {
                        dataFromServer = string.Empty;

                        sock.ConnectAsync(socketEventArg);
                    }
                    catch (SocketException ex)
                    {
                        throw new SocketException(ex.ErrorCode);
                    }
                }
                else
                {
                    sock.Close();
                    sock.Dispose();

                    ResponseReceivedEventArgs args = new ResponseReceivedEventArgs();
                    args.isError = true;
                    OnResponseReceived(args);
                }
            }
        }

The method calls ReceiveAsync again if BytesTransferred is not 0. I also put in a retry loop in because I found on the emulator, the connection seemed to get reset a lot which was annoying (it works nicely on the phone).

HTTP Over Sockets
Now we have a way of sending and receiving data over TCP, we need to work out how to do an HTTP GET. This is where  WireShark comes in again to look at the structure of the message.

The implemented code looks like this:

private void button2_Click(object sender, RoutedEventArgs e)
        {
            // GET string
            string getString = "GET /api/3.0/threads/listPosts.json?forum=abcd&thread:ident=12345&api_key=abcdef0123456789 HTTP/1.0\r\n";
            // Headers
            getString += "Host: disqus.com\r\n";
            getString += "Connection: keep-alive\r\n";
            // This carriage return is important to separate the content
            getString += "\r\n";
            // If this was a POST, content goes here

            AsyncSocketClient client = new AsyncSocketClient("disqus.com", 80);
            client.ResponseReceived += new ResponseReceivedEventHandler(GetCommentsRequestComplete);
            client.SendData(getString);
        }

        private void GetCommentsRequestComplete(object sender, ResponseReceivedEventArgs e)
        {
            // Client
            var client = sender as AsyncSocketClient;
            client.ResponseReceived -= this.GetCommentsRequestComplete;
            client = null;

            if (!e.isError)
            {
                // Strip off http preamble
                int start = e.response.IndexOf('{');
                string data = e.response.Substring(start);
            }
        }

I started with a full set of headers from the browser analysis, then removed the ones that aren't needed one by one to keep the code more manageable. The "Connection" header is really important, if you use value as "close" the socket will shut down before all data is received, so "keep-alive" must be used.

Conclusion
I've actually used this solution twice already now and think it will come in useful again and again. I hope other people having this same problem find this as it works nicely!