1 Comments

During today’s Windows Phone development session I encountered a problem with the application bar icons. The problem was simple: The application bar and its icons worked correctly inside the startup project but my pages inside the secondary project didn’t show the application bar icons.  I had the icons inside the secondary project and I checked million times that their build action was set to Content. And that was the problem: I forgot that the application bar icons must always be inside the startup project.

I suppose this is basic stuff and I should have known better, but sometimes these just take too much time to solve so hopefully the following helps someone else fighting with the same problem.

So, to solve my problems I had to do the following:

  1. Move the icons from the secondary module into the startup project
  2. Leave the IconUri-property as it was. No component keyword, nothing.

Now the startup project contains the icons:

image

The secondary module project contains the page and no icons:

image

The page inside the secondary module references the icons as if they were inside its own project:

image

ReSharper will tell you that the file doesn’t exist but it still works.

8 Comments

Background

imageBefore the Mango update, Windows Phone developers were advised against using the application bar with a Panorama control. This was somewhat changed with the Mango which includes  a new minimized mode for the application bar. This mode can be accessed using the Mode-property of the application bar.

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True" Mode="Minimized">

For example the built-in People hub uses this new mode. But if you cycle through the panorama items in the People hub, you’ll notice that there’s one panorama item where the application bar is shown in its default mode. This is a nice behavior because it draws the user’s attention  to the functionalities provided by the application bar. And this same behavior has been replicated by many 3rd part applications. But be careful with it, because in its current state, changing between the two different modes may cut some pixels from your panorama’s background.

The problem

The problem manifests itself if you meet the following conditions in you app:

  • You have a page which includes the panorama
  • You have an application bar
  • You’re switching between the two different app bar modes (minimized / default)
  • User can arrive to the panorama page so that the app bar is in default mode.

When the panorama is first drawn with the application bar in default mode, it doesn’t draw the background properly when the app bar is switched to the minimized mode.

Let’s go through some examples.

Example 1: Application starts with the application bar in minimized mode

If the app bar is in minimized mode when the app is started, everything works correctly:

Application bar minimized:

 

image

Application bar in default mode:

image

Example 2: Application starts with the application bar in default mode

If the app bar is in default mode when the app is started, the background loses some pixels when the app bar is minimized:

Application bar in default mode:

image

Application bar minimized:

image

As you can see, the background is cut. This happens also with the first example if the user is able to navigate forward when the application bar is in default mode. When the user navigates back, the background doesn’t draw correctly.

Workaround

Until the bug is fixed, probably the simples workaround is to set application bar’s opacity to less than 1.

        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True" Mode="Default" Opacity="0.99">
            <shell:ApplicationBarIconButton IconUri="appbar.questionmark.rest.png" Text="help"/>
        </shell:ApplicationBar>

Example 3: Application starts with the application bar in default mode and the application bar’s opacity is less than 1

If the app bar is in default mode when the app is started, and its opacity is less than 1, everything works correctly:

Application bar in default mode:

image

Application bar minimized:

image

8 Comments

Windows Phone Mango adds the ability to create secondary tiles for your applications. We have recently upgraded most of our applications to the Mango and in doing so, few of our apps now allow users to add “deep links” to the Start menu, in the form of secondary tiles. Imagine an app where the first page (MainPage.xaml) shows a list of products and the selection of a product takes him/her to the next page for product details (ProductDetails.xaml). A deep link is an application startup tile which opens the app from the ProductDetails.xaml instead of the MainPage.xaml.

Deep links and the back button

Creating these deep links is a straightforward task using the tools provided by the Windows Phone platform, but what we didn’t anticipate is that these links cause a design issue: What should happen when the user starts the application using a deep link and then presses the Back-button?We did some search on this question and didn’t find any guidance so we followed our initial idea: the back button should take the user to app’s main page. Turns out we were wrong.

Since then Peter Torr has written an excellent guidance for this specific design issue. The main point from his post is that the back button should always take the user back to the previous page. If the previous page is the Start menu, then so be it.

Pinned secondary tiles for marketplace applications should behave exactly the same way. Tapping on a tile should deep-link directly into the content that the user pinned, and the Back key should always exit the application and return to Start.

Home button

The design dilemma between the deep links and the back button also touches an another issue: The home button. Windows Phone design guidelines have previously stated that the application shouldn’t have a Home-button. But in some situations it would be handy if the user could navigate to the main page of your application even if the app has been started from a deep link. Peter Torr shortly discusses this issue in his post so I recommend to check it out.

We have found the home button very useful when used in combination with the deep linkis. Some of our apps have the home button and it is really useful in these situations. Even though it is against the design guidelines, we think it improves the usability so much that we are going to use it also in the future.

Links:

7 Comments
Advert: IRC7 is theIRC-client for Windows Phone 7. Learn more at www.softwaremk.org/irc.

This is the part III of a tutorial series which will describe the WP7’s sockets-support from a developer’s perspective. This tutorial series will focus on developing WP7 applications which require a long running TCP-connection that send and receive text-based data. In these posts we will go through of building a complete IRC-client.

The focus of these posts is in the WP7’s developer’s perspective. If you want to better understand the inner details of the Internet sockets, Wikipedia has a good introduction on the subject.

We’re almost there. We have opened the connection to the server and we have also received some messages from it. But, we must identify ourselves to the server which we’re not doing yet. This means that we’re not following the IRC-specification, making the server close our connection almost immediately. In this tutorial we will start sending messages to the server.

Background

The IRC-specification states the following:

The recommended order for a client to register is as follows:

  1. Pass message
  2. Nick message
  3. User message

… The PASS command is used to set a 'connection password'.

… NICK message is used to give user a nickname or change the previous one.

… The USER message is used at the beginning of connection to specify the username, hostname, servername and realname of s new user. It is also used in communication between servers to indicate new user arriving on IRC, since only after both USER and NICK have been received from a client does a user become registered.

The server is currently disconnecting us because we’re not sending the required messages to the server. In this tutorial we can skip the PASS-message completely, because it’s only required when connecting to a password protected server. But, we have to send the NICK and USER-messages.

The syntax for the messages are listed in the specification:

Command:    NICK
Parameters:    <nickname>

Command:    USER
Parameters:    <username> <hostname> <servername> <realname>

The code

The server is now waiting for us to identify ourselves. We do this by sending the NICK and USER-messages with the correct parameters. Sending a message to the server happens through our Socket-instance’s SendAsync-method. Similar to receiving a message,  we need a buffer and a SocketAsyncEventArgs-class to do this. We could handle the Completed-event from the SocketAsyncEventArgs-instance to get a notification when the message has been send but we’re going to skip this part: If the connection is open, there’s no reason for the sending to fail.

        public void SendToServer(string message)
        {
            var asyncEvent = new SocketAsyncEventArgs { RemoteEndPoint = new DnsEndPoint(server, serverPort) };

            var buffer = Encoding.UTF8.GetBytes(message + Environment.NewLine);
            asyncEvent.SetBuffer(buffer, 0, buffer.Length);

            connection.SendAsync(asyncEvent);
        }

Every message we send must end with a newline.If the newline is missing, the server won’t process the message and this can cause problems which are hard to debug. Because of this we always add the newline to the message inside the SendToServer-message.

The NICK-message

Every user in the IRC-sever has a nick. This is their unique ID and also a display name which other users see. Sending the NICK-message to the server sets your  unique nick name. Currently our IrcClient.cs raises the CreateConnectionCompleted-event when a connection has been established to the server and we use this event to notify our application so that it can ask the IrcClient to send our NICK to the server.

        private void OnCreateConnectionCompleted(object sender, CreateConnectionAsyncArgs e)
        {
            if (!e.ConnectionOk)
            {
                UpdateStatus("Connection failed");
                return;
            }

            UpdateStatus("Connection OK");

            SendCredentialsToServer();
        }

        private void SendCredentialsToServer()
        {
            var myNickName = "myNick " + DateTime.Now.Millisecond;

            client.SendToServer("NICK " + myNickName);
        }
The USER-message

Sending the NICK-message isn’t enough because the server expects to see the USER-message also. The syntax for this message is little harder: <username> <hostname> <servername> <realname>. Especially the hostname and servername –parameters may be hard to figure out. But, things get easier when we figure out that those parameters aren’t actually needed and one can hardcode the values ‘0’ and ‘*’ instead. So the only parameters we have to deal with are the username and the realname.

Many people use their email-addresses as their realname. And even more people use their nicknames in both the username and realname variables. It’s up to you (or the user) to decide how much info you want to give out of yourself to the other users. We’re going to use our nickname in both of the parameters:

        private void SendCredentialsToServer()
        {
            var myNickName = "myNick " + DateTime.Now.Millisecond;
            client.SendToServer("NICK " + myNickName);

            var userMessage = string.Format("USER {0} 0 * :{1}", myNickName, myNickName);
            client.SendToServer(userMessage);
        }

Almost there

Based on our previous knowledge this should be enough. We’re sending the NICK-message and the USER-message. And in some cases this would be enough but because we are trying to connect to a QuakeNet-server, it isn’t. If you execute the code now you will see some new messages. First, there’s a PING-message with a random number after it. And then, little later the server will close the connection because “Your client may not be compatible with this server.”

image

The problem is that the server expects us to answer to the PING-message. This is done by sending it a PONG-message with the same random number it sent us. This doesn’t happen only when connecting to the server: As long as you are connected to the server, you will receive these PING-messages from time to time. And you always have to respond to them or the server will close the connection.

Some servers send the PING-message withoutthe ‘:’-character. This is one of the big problems when creating a well-working IRC-client: There’s these small differences between the servers which makes parsing the messages rather hard.

So, we must read the number from the PING-message and send the correct PONG-message to the server. For this we’re going to create a new MessageObserver-class which will register to the client’s IrcMessageReceivedFromServer-event, parse the received PING-message and send the answer. First we create the new class:

    public class MessageObserver
    {
        private readonly IrcClient client;

        public MessageObserver(IrcClient client)
        {
            this.client = client;

            this.client.IrcMessageReceivedFromServer += OnIrcMessageReceivedFromServer;
        }

        private void OnIrcMessageReceivedFromServer(object sender, IrcMessageReceivedFromServer e)
        {
        }
    }

And then we create a one instance of it in the same place where the IrcClient-instance is created, in our MainPage’s constructor:

        public MainPage()
        {
            InitializeComponent();

            this.client = new IrcClient();
            this.client.CreateConnectionCompleted += OnCreateConnectionCompleted;

            this.observer = new MessageObserver(client);
        }

Now we just need to create the required parsing logic for the PING-message:

        private void OnIrcMessageReceivedFromServer(object sender, IrcMessageReceivedFromServer e)
        {
            if (string.IsNullOrWhiteSpace(e.Message))
                return;

            if (e.Message.IndexOf("PING :") == 0)
            {
                HandlePing(e.Message);
                return;
            }
        }

        private void HandlePing(string message)
        {
            var index = message.LastIndexOf(":");
            var pingNumber = message.Substring(index + 1);

            var pongMessage = string.Format("PONG :{0}", pingNumber);
            client.SendToServer(pongMessage);
        }

Current functionality

imageAfter these modifications our app is ready from the server connection’s point of view. We can connect to the server and send and receive messages with it. We’re now in point where the server sends us the MOTD (message of the day) message, welcoming us to the server.

Because our app can respond to the PING-messages, it can stay connected to the server as long as it wants. The app isn’t very useful yet because it outputs only into the Visual Studio’s output-window and it doesn’t have a textbox for sending messages to the server. But we have the framework on which we can build on. It’s now just about adding more features.

Next steps

We are off to a good start but there’s still many topics to discuss about:

  • Debugging the socket-connections
  • Adding some basic functions: Joining a channel and sending a message to it
  • Handling application switching / tombstoning

Source code

The whole source code for this tutorial is available from the GitHub.

Links

18 Comments
Advert: IRC7 is theIRC-client for Windows Phone 7. Learn more at www.softwaremk.org/irc.

This is the part II of a tutorial series which will describe the WP7’s sockets-support from a developer’s perspective. This tutorial series will focus on developing WP7 applications which require a long running TCP-connection that send and receive text-based data. In these posts we will go through of building a complete IRC-client.

The focus of these posts is in the WP7’s developer’s perspective. If you want to better understand the inner details of the Internet sockets, Wikipedia has a good introduction on the subject.

This second installment will continue from where the first part stopped: We have the TCP-connection open and now we must start listening to the messages that the server sends us.

Basics

Like we previously went through, the Socket and the SockectAsyncEventArgs are the two key classes when dealing with sockets in Windows Phone platform. They are used when a connection is created and they are used again when we want to receive messages from the server. We are going to continue with the pattern we established in the first tutorial: An instance of the SockectAsyncEventArgs is always used just once and then disposed.

To receive a message we need a buffer. The buffer is simply an array of byte which is created and attached to the SocketAsyncEventArgs-instance. When the server sends a message to our client, it may or may not fit into a single buffer. If it doesn’t fit, the rest of the message (or the next part) can be received by again creating a new SocketAsyncEventArgs-instance and a buffer for it.

Creating a new buffer for every message is not the only available solution. One could use a Circular buffer to optimize things performance wise. You can check out the “Circular Buffer for .NET”, a project from CodePlex, to see an example implementation.

The code

Like previously mentioned, in addition to the byte array we need an instance of the SocketAsyncEventArgs to receive a message from the server. This is passed to the ReceiveAsync-method of our socket-instance.

        private void ReceiveMessage()
        {
            var responseListener = new SocketAsyncEventArgs();
            responseListener.Completed += OnMessageReceivedFromServer;
            
            var responseBuffer = new byte[bufferSize];
            responseListener.SetBuffer(responseBuffer, 0, bufferSize);

            connection.ReceiveAsync(responseListener);
        }

The new ReceiveMessage-method can be called after the connection to the server has been opened. Now, when the server sends us a message, our method OnMessageReceivedFromServer is executed. In this method we need to do few things:

  1. Convert the buffer (the byte-array) into a string. This is the message (or the messages) that the server sent us.
  2. Parse the message and react to it according to the IRC-specification.
  3. Call the ReceiveMessage-method which will create a new buffer and a new SocketAsyncEventArgs and starts listening for the next message from the server.

One buffer can contain multiple messages from the server.Server can send multiple messages to us, meaning that the even though the OnMessageReceivedFromServer is executed only once, there may be multiple messages we have to deal with. In the IRC-protocol every message ends with a newline and we can use this to our advantage: After turning the byte-array into a string, we split it by the newline characters into a string-array. Every instance in the array is one individual message from the server.

But how can we be sure that the server’s message fit into our buffer? If the last character in the buffer is a newline, all is well. But if it isn’t, our buffer is full and there’s a new message waiting for us. And we have to do some stitching: We can’t process the current message because it’s not complete so we store it into a variable, wait for the next message and combine those two. Using the previously mentioned circular buffer would make this somewhat easier.

        private string trailingMessage;
        private void OnMessageReceivedFromServer(object sender, SocketAsyncEventArgs e)
        {
            // Convert the received message into a string
            var message = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);

            var bufferWasPreviouslyFull = !string.IsNullOrWhiteSpace(trailingMessage);
            if (bufferWasPreviouslyFull)
            {
                message = trailingMessage + message;
                trailingMessage = null;
            }

            var isConnectionLost = string.IsNullOrWhiteSpace(message);
            if (isConnectionLost)
            {
                // We lost the connection for some reason
                // Handle the situation
                return;
            }

            // Convert the received string into a string array
            var lines = new List<string>(message.Split("nr".ToCharArray(), StringSplitOptions.None));

            var lastLine = lines.LastOrDefault();
            var isBufferFull = !string.IsNullOrWhiteSpace(lastLine);
            if (isBufferFull)
            {
                trailingMessage = lastLine;
                lines.Remove(lastLine);
            }

            foreach (var line in lines)
            {
                if (string.IsNullOrWhiteSpace(line))
                    continue;

                ProcessIncomingMessage(line);
            }

            // Start listening for the next message
            ReceiveMessage();
        }

Now we just have to implement the ProcessIncomingMessage-method. In this method we will parse the message and react to it accordingly. It may contain a private message from an another user, a server check to make sure we’re still alive or anything else mentioned in the IRC specifications.

As you can see, we presume that the incoming message is UTF8-encoded. Unfortunately we can’t be sure of this. The IRC-protocol doesn’t dictate on what encoding should be used and this may vary between the clients. The UTF8 is nowadays the most used encoding so we use it.

At this point we’re going to just echo the message into our Debug-output but we’re going to add some basic parsing logic in the future episodes of this tutorial series.

        private void ProcessIncomingMessage(string ircMessage)
        {
            Debug.WriteLine(ircMessage);

            // Future hook for handling the message in somewhere else.
            // It's most probably wise to put the parsing logic in some other class.
           if (IrcMessageReceivedFromServer != null)
               IrcMessageReceivedFromServer(this, new IrcMessageReceivedFromServer(ircMessage));
        }

Current functionality

Now we’re almost there. We can already connect to a server and receive messages from it. You can see this in action if you run our app with the new code we have added in this tutorial.

image

But, if you let the app run long enough, you’ll also notice that we get two additional messages. One states that there has been an error and the other is just an empty string. The first message is received because we didn’t follow the IRC-specification: The server wants us to identify ourselves before it continues. Because we didn’t, the server disconnects our connection and the empty string is received because of this. If we try to call the ReceiveMessage-method after receiving the empty string, we will get an exception because the connection isn’t open anymore.

The next step

The next step is to start following the IRC-specification and actually send messages to the server. We will go through of this in the next part tomorrow.

Source code

The whole source code for this tutorial is available from the GitHub.

Links