Saturday, September 28, 2013

The Bing Challenge

I took the Bing Challenge and Bing … didn’t win. Google beat them 4 to 1.

Bing has a prettier results page, but it got some things wrong. I searched for “Improv Spokane” and I got a beautiful map of major Home Improvement stores in Spokane Washington. I know the improv scene in Spokane and I would have expected to see the Blue Door Theatre in the top 3 of that search. It was #1 with Google (and Yahoo!), but below the fold on Bing. Bing did do a better job on “Improv Seattle”.

On the other 4 searches, Bing did an acceptable job, I did vote for Google for all but “Gracie Allen”, but I wouldn’t have been disappointed with any of the 3 other results. To me it feels as if Bing is focusing on the most popular results and going down from there. With its ten years or so head start, Google has built a giant pile of data and logic.

Since I’m a contractor at Microsoft right now, I actually use Bing a fair amount: 90% at work and 25% at home. Even before I got my current job I used Bing 20% of the time. Bing is slowly getting better and that’s a good thing. We need more than Google in the popular search space.

Saturday, August 31, 2013

Humorous Speech

Last week I participated in a humorous speech contest at Toastmasters. I didn’t win, I was second of three.

I can be funny as part of a normal speech, I can get one or two laugh lines I to a 5 to 7 minute speech. Since the purpose of the speech is to be funny, I kinda freak out.

In a humorous speech the audience is expecting me to be funny, so I can’t use the element of surprise. In a normal speech, a failed joke doesn’t necessarily sink the speech.

In a humorous speech the audience is expecting higher joke density. My usual Toastmaster speech has two laugh lines and perhaps an unintentional joke hidden within. So I need to triple my joke count without them sounding forced.

There is a big difference between the fellow who is funny and the comedian; any time the civilian is funny it is a bonus, any time the pro fails to be funny it is a failure.

Wednesday, July 31, 2013

Take Improv after you move

At the beginning of June I moved from Spokane to Bellevue to work at Microsoft. I signed up for improv class with Unexpected Productions even before I left Spokane. This was a brilliant move! The quarter ended last night, which makes me sad. I have already signed up for the 200 level class that starts in September.

Since then I have gone to the Matador (a Mexican themed bar in downtown Redmond) after a couple of my classes, to a couple of shows with some classmates, found a Toastmasters club (again with a couple of classmates who already belong).

Pre-improv Jack would still be hanging out alone in his apartment two months out after moving to a new city. My previous improv experience has given me some better social skills than I had before; improv class creates openness in the students.

If I ever move again I will look for improv classes in my new community. I will start at the beginning (even if I become a player at UP) and move up with my class. My objective isn’t necessarily to become a great improviser, but to have the opportunity to play and become more skilled at dealing with people (as opposed to technology).

I know that both readers of this blog are probably saying “enough of this improv stuff already!” This stuff has worked for me and I am excited about the results. I don’t know that pre-improv would have gotten this job. It has given me the courage to get up in front of people in non-improv situations; I have spoken at a half dozen code camps and I am working the Toastmasters program.

Even if I’m a really bad improviser, it’s worth it.

Wednesday, June 26, 2013

Back at Microsoft

I took another contract job at Microsoft; back for the first time in almost 13 years. I started at the beginning of June. I’m excited to work on cutting edge technology with smart people (try to be the dumbest person in the room if you can).

What am I working on? I can’t say.

Thursday, May 09, 2013

NPR Teenage Diaries Revisited on Tourette’s

On NPR’s All Things Considered, they did a story on Josh Cutler and his experience with Tourette’s syndrome. It got me to think about, my own experience,so I wrote this letter to Josh through NPR’s comment page.

Josh Cutler,

I don’t know what you will say about having Tourette’s at 50, however I can tell you about my experience at 49.

In my generation, we weren’t all that aware of Tourette’s, I was just a troubled kid in Special Education who wasn’t supposed to go to college (but I did graduate from Central Washington University in 5 years). I wasn’t diagnosed until after I turned 40.

Now I am a computer programmer. I’ve worked for many small companies and one really large one. I think I do solitary work because I don’t trust my behavior. I admire you for having the guts to teach; I’m sad that it didn’t go well. I wish the world would be more supportive of people like us. I relate to children, I’m scared of adult’s reaction to me.

I totally relate with your jujitsu class; over the last few years I’ve been taking this Improv class over and over again; I believe that keeps me sane. I walk over a mile to work everyday day. The motion of the scene work and walking all over town helps me keep my ticks in check. I think the Improv has been good to me because it allows me to play with behavior and just be childlike among other grown-ups.

Most of my ticks are in my face shoulder, leg neck and elsewhere in my body. At times the energy behind the twitch can become overwhelming; sometimes I will shake all over for an hour at night. I’ve twitched to the point of pain. I don’t cuss, I have trouble saying the F-word in the locker room where I’m supposed to have a foul mouth. I do have a problem with “angry” outbursts.

I too had my bad Tourette’s event with long term consequences. My incident happened at Microsoft in 2000. I had been “normal” for over a year and then I burst. So, based in a moderate episode I am banned from ever working there again, and as far as I can tell, it is still in force. [NOTE: it isn't still in force, see my next post]

The curse of Tourette’s is that it leads to bazaar behavior. When I’ve behaved badly it is scary because it is different, not because it is necessarily dangerous.

Thank you, Josh, for sharing your life with us. It means a lot to me. You’ve given me the opportunity to put things into words.

Best of luck

Jack Stephens

Spokane

I think there is a point where it is good to put it out there.

Sunday, April 14, 2013

Compare two DataSets for testing

There is a client that has several statements that are rendered as Crystal Reports; we bind the Crystal Reposts to ADO.NET DataSets. The DataSets are loaded from stored procedures in the usual way. Right now we are printing several of these statements and some poor clerk has to compare those values with an earlier correct one.

My idea is to store the DataSets of known good statements and then I can automatically compare them with a new DataSet loaded from the stored procedure. So, over the weekend I wrote these classes to do the comparisons:

The Code

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace CompareDS
{
    /// <summary>
    /// Compare the contents of DataSets or DataTables 
    /// </summary>
    public class CompareDataSet
    {
        /// <summary>
        /// Compare the content of two DataSets
        /// </summary>
        /// <param name="fromDS">The DataSet considered to be correct</param>
        /// <param name="toDS">The DataSet to be tested</param>
        /// <returns>A list of Inconsistencies</returns>
        public static List<CompareDifference> DoCompareDataSet(
            DataSet fromDS, DataSet toDS)
        {
            var rVal = new List<CompareDifference>();

            // Make sure that the table count match
            if (fromDS.Tables.Count != toDS.Tables.Count)
            {
                rVal.Add(new CompareDifference
            {
                Message = string.Format("Non maching # of tables: {0} != {1}", 
                    fromDS.Tables.Count, toDS.Tables.Count)
                });
            }
            // Process the smaller # of tables
            int minColCount = Math.Min(fromDS.Tables.Count, toDS.Tables.Count);
            for (int i = 0; i < minColCount; ++i)
            {
                DataTable fromTable = fromDS.Tables[i];
                DataTable toTable = toDS.Tables[i];
                string tableName = fromTable.TableName;
                rVal.AddRange(DoCompareTable(fromTable, toTable, tableName, i));
            }
            return rVal;
        }
        /// <summary>
        /// Compare the content of two DataTables
        /// </summary>
        /// <param name="fromTable">The DataTable considered to be correct</param>
        /// <param name="toTable">The DataTable to be tested</param>
        /// <param name="tableName">The Name of the table to be compared</param>
        /// <param name="tableNumber">The zero based table number</param>
        /// <returns>A list of Inconsistencies</returns>
        public static List<CompareDifference> DoCompareTable(DataTable fromTable, 
            DataTable toTable, string tableName = "Table", int tableNumber = 0)
        {
            var rVal = new List<CompareDifference>();
            // Number of Rows should match
            if (fromTable.Rows.Count != toTable.Rows.Count)
            {
                rVal.Add(new CompareDifference
                {
                    TableName = tableName,
                    TableNumber = tableNumber,
                    Message = string.Format("Non maching # of rows: {0} != {1}", 
                        fromTable.Rows.Count, toTable.Rows.Count)
                });
            }
            // Create new CompareDataTable for this table
            var compTables = new CompareDataTable     (fromTable, toTable, 
                tableName, tableNumber);
            int minColCount = Math.Min(fromTable.Rows.Count, toTable.Rows.Count);
            for (int i = 0; i < minColCount; ++i)
            {
                rVal.AddRange(compTables.CompareRow(
                    fromTable.Rows[i], toTable.Rows[i], i));
            }
            return rVal;
        }
    }
    /// <summary>
    /// Compares a DateTable row by row.
    /// I use a seperate non-static class so I don't have to re-aquire
    /// the table's Columns (Overkill, I know)
    /// </summary>
    public class CompareDataTable
    {
        private DataTable _fromTable;
        private DataTable _toTable;
        private DataColumnCollection _fromColumns;
        private DataColumnCollection _toColumns;
        private string _tableName;
        public int _tableNumber;

        /// <summary>
        /// Constructor: I use this class to avoid re-aquiring Columns
        /// for each row.
        /// </summary>
        /// <param name="fromTable">The DataTable considered to be correct</param>
        /// <param name="toTable">The DataTable to be tested</param>
        /// <param name="tableName">The Name of the table to be compared</param>
        /// <param name="tableNumber">The zero based table number</param>
        public CompareDataTable(DataTable fromTable, DataTable toTable, 
            string tableName, int tableNumber)
        {
             _fromTable = fromTable;
             _toTable = toTable;
             _tableName = tableName;
             _tableNumber = tableNumber;

             // Remember the Table Columns
             _fromColumns = _fromTable.Columns;
             _toColumns = _toTable.Columns;
        }
        /// <summary>
        /// Compare the content of two DataRows
        /// </summary>
        /// <param name="fromRow">The DataRow considered to be correct</param>
        /// <param name="toRow">The DataRow  to be tested</param>
        /// <param name="rowNumber">The zero based number of the row</param>
        /// <returns>A list of Inconsistencies</returns>
        public List<CompareDifference> CompareRow(DataRow fromRow, 
        DataRow toRow, int rowNumber)
        {
            var rVal = new List<CompareDifference>();
            int minColCount = Math.Min(fromRow.ItemArray.Count(), 
            toRow.ItemArray.Count());

            for (int i = 0; i < minColCount; ++i)
            {
                object fromCell = fromRow.ItemArray[i];
                object toCell = toRow.ItemArray[i];
                string fromColName = _fromColumns[i].ColumnName;
                string toColName = _toColumns[i].ColumnName;
                // Column names must match
                if (fromColName != toColName)
                {
                    rVal.Add(new CompareDifference
                    {
                        TableName = _tableName,
                        TableNumber = _tableNumber,
                        RowNumber = rowNumber,
                        ColumnName = fromColName,
                        ColumnNumber = i,
                        Message = string.Format(
                            "Non matching column names \"{0}\" != \"{1}\"", 
                            fromColName, toColName)
                        });
                }
                // Type must match
                if (fromCell.GetType() != toCell.GetType())
                {
                    rVal.Add(new CompareDifference
                    {
                        TableName = _tableName,
                        TableNumber = _tableNumber,
                        RowNumber = rowNumber,
                        ColumnName = fromColName,
                        ColumnNumber = i,
                        ExpectedValue = fromCell.ToString(),
                        ActualValue = toCell.ToString(),
                        Message = string.Format(
                            "No matching types \"{0}\" != \"{1}\"", 
                            fromCell.GetType(), toCell.GetType())
                    });
                }
                // And values (string compare for simplicity)
                else if (fromCell.ToString() != toCell.ToString())
                {
                    rVal.Add(new CompareDifference
                    {
                        TableName = _tableName,
                        TableNumber = _tableNumber,
                        RowNumber = rowNumber,
                        ColumnName = fromColName,
                        ColumnNumber = i,
                        ExpectedValue = fromCell.ToString(),
                        ActualValue = toCell.ToString(),
                        Message = string.Format(
                            "No matching values \"{0}\" != \"{1}\"", 
                            fromCell, toCell)
                    });
                }
            }
            return rVal;
        }
    }
    /// <summary>
    /// Simple class to store error messages
    /// </summary>
    public class CompareDifference
    {
        /// <summary>
        /// The Name of the Table 
        /// where the inconsistancy exists
        /// </summary>
        public int TableNumber { get; set; }
        /// <summary>
        /// The zero based number of the Table 
        /// where the inconsistancy exists
        /// </summary>
        public string TableName { get; set; }
        /// <summary>
        /// The zero based number of the column
        /// where the inconsistancy exists
        /// </summary>
        public int? ColumnNumber { get; set; }
        /// <summary>
        /// The name of the column
        /// where the inconsistancy exists
        /// </summary>
        public string ColumnName { get; set; }
        /// <summary>
        /// The number of the row 
        /// where the inconsistancy exists
        /// </summary>
        public int? RowNumber { get; set; }
        /// <summary>
        /// The expected value
        /// </summary>
        public string ExpectedValue { get; set; }
        /// <summary>
        ///  The actual value
        /// </summary>
        public string ActualValue { get; set; }
        /// <summary>
        /// An error message
        /// </summary>
        public string Message { get; set; }
    }
}

Sunday, March 10, 2013

Displaying Status with Live Tiles

Brain Dead Simple Windows RT App Part 4

In Windows Phone, Microsoft introduced the idea of Tiles that could provide the use with updates. Your tile is important because it is the one thing that is always there whispering to the user “run me” day and night. There are four types of updates, Local, Scheduled, Periodic and Push. Because this is a basic level intro article, I’m going to ignore Scheduled, Periodic and Push and work on Local (in the wild, you will probably need to use one of the other three).

Windows 8 offers a total of 46 tile templates that are enumerated in TileTemplateType. To update a tile you:

  1. Get the Template with TileUpdateManager.GetTemplateContent
  2. Create a notification or a new TileNotification object with a reference to the template you retrieved on Step 1 and set any ExpirationTime
  3. Set notification text on the Template XML you retrieved on Step 1
  4. Update Live Tile Create a TileUpdater and call its Update with a the TileNotification created in Step 1

Back to the App

I’m lazy, so I don’t even want to open my app to know how excited I am. I can use the apps tile to remind me. Now I only need to open the app to use the more advanced features like changing my excitement level.

NOTE: In this app, the settings roam but the Live Tile does not. Since this is a really simple demo, I’m OK with that, I would never ship an app like this.

public static void SetLiveTile(string title, string body, int? seconds = null)
{
    // Get tile template.
    var tileTemplate = TileTemplateType.TileSquareBlock;
    XmlDocument tileXml = TileUpdateManager.GetTemplateContent(tileTemplate);

    // Create notification.
    var notification = new TileNotification(tileXml);
    if (seconds.HasValue)
    {
        notification.ExpirationTime = DateTime.Now + 
        TimeSpan.FromSeconds(seconds.Value);
    }

    // Set notification text.
    XmlNodeList nodes =    tileXml.GetElementsByTagName("text");
    nodes[0].InnerText = title;
    nodes[1].InnerText = body;

    // Update Live Tile.
    var upd = TileUpdateManager.CreateTileUpdaterForApplication();
    upd.Update(notification);
}

And I add the following line to the end of saveSettings()

SetLiveTile(string.Format("{0}!", _exlamationPointCount), HelloMessage, 3600);

Complete Code


using System;
using System.ComponentModel;
using Windows.Data.Xml.Dom;
using Windows.Storage;
using Windows.UI.Notifications;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace HelloWindows
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private const string BASE_MESSAGE = "Hello Windows";

        public MainPage()
        {
            this.InitializeComponent();

            // Load Settings here:
            loadSettings();
            HelloMessage = setMessge(_exlamationPointCount);
            this.DataContext = this;
        }


        private void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new  PropertyChangedEventArgs(propertyName));
            }
        }

        public string HelloMessage { get; set; }


        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.  
        /// The Parameter property is typically used to configure the page.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }

        private int _exlamationPointCount = 0;

        private string setMessge(int exlamationPointCount)
        {
            if (exlamationPointCount > 0)
            {
                return _baseMessage + new string('!', exlamationPointCount);
            }
            else
            {
                return _baseMessage;
            }
        }

        private void addPoint_Click(object  sender, RoutedEventArgs e)
        {
            HelloMessage = setMessge(++_exlamationPointCount);
            RaisePropertyChanged("HelloMessage");
            RaisePropertyChanged("IsRemovePossible");
            // This is overkill
            saveSettings();
        }

        private void removePoint_Click(object sender, RoutedEventArgs e)
        {
            if (_exlamationPointCount >= 1)
            {
                HelloMessage = setMessge(--_exlamationPointCount);
                RaisePropertyChanged("HelloMessage");
                RaisePropertyChanged("IsRemovePossible");
                // This is overkill
                saveSettings();
            }
        }

        // Make it possible to disable Remove Point button when there
        // is nothing left to remove
        public bool IsRemovePossible
        {
            get { return _exlamationPointCount > 0; }
        }
        // I replace most refrence to BASE_MESSAGE to _baseMessage
        private string _baseMessage = BASE_MESSAGE;

        // Ensure that RoamingSettings has been loaded
        private static ApplicationDataContainer _roamingSettings;
        public static ApplicationDataContainer RoamingSettings
        {
            get
            {
              if (_roamingSettings == null)
              {
                  // If I don't want roaming, use 
                  // ApplicationData.Current.LocalSettings;
                  _roamingSettings = ApplicationData.Current.RoamingSettings;
              }
              return _roamingSettings;
            }
        }

        // I know that saving every time the value is changed,
        // in real life I'd save the data in App.OnSuspending()
        private void saveSettings()
        {
            // I combine both values into a ApplicationDataCompositeValue
            // and save them both to "HighPriority"
            var composite = new ApplicationDataCompositeValue();
            composite["baseMessage"] = _baseMessage;
            composite["exlamationPointCount"] = _exlamationPointCount;
            RoamingSettings.Values["HighPriority"] = composite;

           SetLiveTile(string.Format("{0}!" , _exlamationPointCount),
           HelloMessage, 3600);
        }
        // To be called from the constructor
        private void loadSettings()
        {
            // I get "HighPriority" cast it to ApplicationDataCompositeValue
            // and extract the values.
            var composite = (ApplicationDataCompositeValue)
            RoamingSettings.Values["HighPriority"];
            if (composite != null) // the first time it will be null
            {
                _baseMessage = (string)composite["baseMessage"];
                _exlamationPointCount = (int)composite["exlamationPointCount"];
          }
      }


      public static void SetLiveTile(string     title, string body, int? seconds = null)
      {
          // Get tile template.
          var tileTemplate = TileTemplateType.TileSquareBlock;
          XmlDocument tileXml = TileUpdateManager.GetTemplateContent(tileTemplate);

          // Create notification.
          var notification = new TileNotification(tileXml);
          if (seconds.HasValue)
          {
              notification.ExpirationTime = DateTime.Now +
              TimeSpan.FromSeconds(seconds.Value);
          }

          // Set notification text.
          XmlNodeList nodes = tileXml.GetElementsByTagName("text");
          nodes[0].InnerText = title;
          nodes[1].InnerText = body;

          // Update Live Tile.
          var upd = TileUpdateManager.CreateTileUpdaterForApplication();
          upd.Update(notification);
      }
    }
}

My Brain Dead Simple Windows RT App: The Series

Thursday, March 07, 2013

Roaming data with ApplicationData

Brain Dead Simple Windows RT App Part 3

In Window 8, you should be able to move between your devices and your apps should follow you. In the Microsoft documentation, there is a lot of talk about some office worker who likes to start some task on her office computer (possibly when her boss’s back is turned) and finish them on the bus with her tablet. The feature that they are pushing with these examples is Roaming.

So by the time that Emily (we can call her that) turns off her computer at work, the app needs to save some state data to the cloud, when she opens the same app on her tablet, it goes out and gets the that data from the cloud and uses it to remember where she left off.

All the stuff you need to do this is in Windows.Storage.ApplicationData. You have a choice of where you want to save it (Roaming or Local) and how (ApplicationDataContainer or StorageFolder).

Roaming data is first stored locally and then pushed to Microsoft servers on the cloud; there is a limit to how much data can be roamed, you can use RoamingStorageQuota to find out how much (note that if you exceed the quota, it will just fail without any errors at all).

Local stores the data locally so no roaming occurs but you have more space to work with and can be used for things that aren’t appropriate to roam.

ApplicationDataContainer (used for RoamingSettings & LocalSettings) contains a property called Values which is a dictionary that contains the settings. Each value in the dictionary is handled separately, so one value may be roamed before the other. You can use ApplicationDataCompositeValue to stick values together and they will be treated as a single unit. Oh, yea, there is a special value in the dictionary called “HighPriority” that will be roamed before everything else.

StorageFolder (used for RoamingFolder, LocalFolder & TemporaryFolder) gives you a handle to a folder in the file system that you can use to read and write files. Files in RoamingFolder will be synced with the magic Microsoft server (if the total size doesn’t exceed RoamingStorageQuota. Files in LocalFolder are not synced but will stay around for a while; the files in TemporaryFolder don’t.

Back to the App

When I run my Hello app, I can press the Exclamation Point Button 42 times but when I close it down and open it up again, if forgets. So, when I open the app again, there are NO exclamation points and that dampens my enthusiasm; I want to keep my excitement so the exclamation points need to stay. We can solve this problem with Roaming!

 

// I replace most refrence to BASE_MESSAGE to _baseMessage
private string _baseMessage = BASE_MESSAGE;

// Ensure that RoamingSettings has been loaded
private static ApplicationDataContainer _roamingSettings;
public static ApplicationDataContainer RoamingSettings
{
    get
    {
        if (_roamingSettings == null)
        {
            //If I don't want roaming, use ApplicationData.Current.LocalSettings;
            _roamingSettings = ApplicationData.Current.RoamingSettings;
        }
        return _roamingSettings;
    }
}

// I know that saving every time the value is changed,
// in real life I'd save the data in App.OnSuspending()
private void saveSettings()
{
    // I combine both values into a ApplicationDataCompositeValue
    // and save them both to "HighPriority"
    var composite = new ApplicationDataCompositeValue();
    composite["baseMessage"] = _baseMessage;
    composite["exlamationPointCount"] = _exlamationPointCount;
    RoamingSettings.Values["HighPriority"] = composite;
}
// To be called from the constructor
private void loadSettings()
{
    // I get "HighPriority" cast it to ApplicationDataCompositeValue
    // and extract the values.
    var composite = (ApplicationDataCompositeValue)
    RoamingSettings.Values["HighPriority"];
    if (composite != null) // the first time it will be null
    {
        _baseMessage = (string)composite["baseMessage"];
        _exlamationPointCount = (int)composite["exlamationPointCount"];
    }
}

And I change the constructor to look like:

public MainPage()
{
    this.InitializeComponent();

    // Load Settings here:
    loadSettings();
    HelloMessage = setMessge(_exlamationPointCount);
    this.DataContext = this;
}

And the setMessage() to the field instead of the constant:

private string setMessge(int exlamationPointCount)
{
    if (exlamationPointCount > 0)
    {
        return _baseMessage + new string('!', exlamationPointCount);
    }
    else
    {
        return _baseMessage;
    }
}

Since I haven’t changed the markup, I won’t repost that part (see my previous post), but I will repost the code behind (MainPage.xaml.cs):

using System.ComponentModel;
using Windows.Storage;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace HelloWindows
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private const string BASE_MESSAGE = "Hello Windows";

        public MainPage()
        {
            this.InitializeComponent();

            // Load Settings here:
            loadSettings();
            HelloMessage = setMessge(_exlamationPointCount);
            this.DataContext = this;
        }


        private void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new  PropertyChangedEventArgs(propertyName));
            }
        }

        public string HelloMessage { get; set; }


        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.  
        /// The Parameter property is typically used to configure the page.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }

        private int _exlamationPointCount = 0;

        private string setMessge(int  exlamationPointCount)
        {
            if (exlamationPointCount > 0)
            {
                return _baseMessage + new string('!', exlamationPointCount);
            }
            else
            {
                return _baseMessage;
            }
        }

        private void addPoint_Click(object      sender, RoutedEventArgs e)
        {
            HelloMessage = setMessge(++_exlamationPointCount);
            RaisePropertyChanged("HelloMessage");
            RaisePropertyChanged("IsRemovePossible");
            // This is overkill
            saveSettings();
        }

        private void removePoint_Click(object sender, RoutedEventArgs e)
        {
            if (_exlamationPointCount >= 1)
            {
                HelloMessage = setMessge(--_exlamationPointCount);
                RaisePropertyChanged("HelloMessage");
                RaisePropertyChanged("IsRemovePossible");
                // This is overkill
                saveSettings();
            }
        }

        // Make it possible to disable Remove Point button when there
        // is nothing left to remove
        public bool IsRemovePossible
        {
            get { return _exlamationPointCount > 0; }
        }
        // I replace most refrence to BASE_MESSAGE to _baseMessage
        private string _baseMessage = BASE_MESSAGE;

        // Ensure that RoamingSettings has been loaded
        private static ApplicationDataContainer _roamingSettings;
        public static ApplicationDataContainer RoamingSettings
        {
            get
            {
                if (_roamingSettings == null)
                {
                    // If I don't want roaming, use 
                    // ApplicationData.Current.LocalSettings;
                    _roamingSettings = ApplicationData.Current.RoamingSettings;
                }
                return _roamingSettings;
            }
        }

        // I know that saving every time the value is changed,
        // in real life I'd save the data in App.OnSuspending()
        private void saveSettings()
        {
            // I combine both values into a ApplicationDataCompositeValue
            // and save them both to "HighPriority"
            var composite = new  ApplicationDataCompositeValue();
            composite["baseMessage"] = _baseMessage;
            composite["exlamationPointCount"] = _exlamationPointCount;
            RoamingSettings.Values["HighPriority"] = composite;
        }
        // To be called from the constructor
        private void loadSettings()
        {
            // I get "HighPriority" cast it to ApplicationDataCompositeValue
            // and extract the values.
            var composite = (ApplicationDataCompositeValue)
            RoamingSettings.Values["HighPriority"];
            if (composite != null           ) // the first time it will be null
            {
                _baseMessage = (string)composite["baseMessage"];
                _exlamationPointCount = (int)composite["exlamationPointCount"];
            }
        }
    }
}

My Brain Dead Simple Windows RT App: The Series

Monday, March 04, 2013

Using App Bars to Hide Chrome

Brain Dead Simple Windows RT App Part 2

In Microsoft’s UX Guidelines for Windows Store apps, they talk about reducing “chrome” and hiding it in well known locations (to anyone who uses Windows 8). A couple of those well known locations are the top and bottom App Bars. Microsoft has very specific recommendations on where commands belong on these things. I will violate those standards and put one button on the top and one on the bottom.

App Bars are hidden UI elements that can be used to hide commands that are too chromey for the main canvas. They appear when you:

  • swipe from the top or bottom of the screen
  • right click your mouse
  • press WindowKey + Z

The Changes

The app fails to express my level of enthusiasm, which can very as time goes on. So, I propose that I add the ability to add and remove exclamation points to the greeting as my mood changes.

I will put a button to add an exclamation point to the Top App Bar (in clear violation of the UX guidelines) and a button to remove exclamation point to the Bottom App Bar.

<Page.TopAppBar>
    <AppBar>
        <StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
            <Button Style="{StaticResource AddAppBarButtonStyle}" 
                Click="addPoint_Click"  />
        </StackPanel>
    </AppBar>
</Page.TopAppBar>
<Page.BottomAppBar>
    <AppBar>
        <StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
            <Button Style="{StaticResource RemoveAppBarButtonStyle}" 
                Click="removePoint_Click" 
                IsEnabled="{Binding Path=IsRemovePossible}"  />
        </StackPanel>
    </AppBar>
</Page.BottomAppBar>

The styles are available in \Common\StandardStyles.xaml, you need to find them and uncomment them or copy them to MainPage.xaml’s Page.Resources (like I did):

<!-- These styles along with many other can be found in \Common\StandardStyles.xaml -->
<Style x:Key="AddAppBarButtonStyle" TargetType="ButtonBase" 
    BasedOn="{StaticResource AppBarButtonStyle}">
        <Setter Property="AutomationProperties.AutomationId" 
            Value="AddAppBarButton" />
        <Setter Property="AutomationProperties.Name" Value="Add" />
        <Setter Property="Content"                 Value="&#xE109;" />
    </Style>    
    <Style x:Key="RemoveAppBarButtonStyle" TargetType="ButtonBase" 
            BasedOn="{StaticResource AppBarButtonStyle}">
        <Setter Property="AutomationProperties.AutomationId" 
            Value="RemoveAppBarButton" />
        <Setter Property="AutomationProperties.Name" Value="Remove" />
        <Setter Property="Content" Value="&#xE108;" />
    </Style>        

So here’s the additional code (I put it at the bottom of my MainPage.xaml.cs), what is does really isn’t important for this post, it just needs to do something to prove that everything is working.

private int _exlamationPointCount = 0;

private static string setMessge(int exlamationPointCount)
{
    if (exlamationPointCount > 0)
    {
        return BASE_MESSAGE + new string('!', exlamationPointCount);
    }
    else
    {
        return BASE_MESSAGE;
    }
}

private void addPoint_Click(object sender, RoutedEventArgs e)
{
    HelloMessage = setMessge(++_exlamationPointCount);
    RaisePropertyChanged("HelloMessage");
    RaisePropertyChanged("IsRemovePossible");
}

private void removePoint_Click(object sender, RoutedEventArgs e)
{
    if (_exlamationPointCount >= 1)
    {
        HelloMessage = setMessge(--_exlamationPointCount);
        RaisePropertyChanged("HelloMessage");
        RaisePropertyChanged("IsRemovePossible");
    }
}

// Make it possible to disable Remove Point button when there
// is nothing left to remove
public bool IsRemovePossible
{
    get { return _exlamationPointCount > 0; }
}

Basically, what I’m doing is keeping track of exclamation point count in _exlamationPointCount. When the buttons are click I increment or decrement the count, make a new message with setMessge() and notify that the properties have been changed.

Complete MainPage Code Listings


MainPage.xaml

<Page
        x:Class="HelloWindows.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:HelloWindows"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">

    <Page.Resources>
    <!-- These styles along with many other can be found in 
        \Common\StandardStyles.xaml -->
        <Style x:Key="AddAppBarButtonStyle" TargetType="ButtonBase" 
                BasedOn="{StaticResource AppBarButtonStyle}">
            <Setter Property="AutomationProperties.AutomationId" 
                Value="AddAppBarButton" />
            <Setter Property="AutomationProperties.Name" Value="Add '!'" />
            <Setter Property="Content" Value="&#xE109;" />
    </Style>
    <Style x:Key="RemoveAppBarButtonStyle" TargetType="ButtonBase" 
                BasedOn="{StaticResource AppBarButtonStyle}">
            <Setter Property="AutomationProperties.AutomationId" 
                Value="RemoveAppBarButton" />
            <Setter Property="AutomationProperties.Name" Value="Remove '!'" />
            <Setter Property="Content" Value="&#xE108;" />
        </Style>        
    </Page.Resources>
    <Page.TopAppBar>
        <AppBar>
            <StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
                <Button Style="{StaticResource AddAppBarButtonStyle}" 
                    Click="addPoint_Click"  />
            </StackPanel>
        </AppBar>
    </Page.TopAppBar>
    <Page.BottomAppBar>
        <AppBar>
            <StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
                <Button Style="{StaticResource RemoveAppBarButtonStyle}" 
                    Click="removePoint_Click" 
                IsEnabled="{Binding  Path=IsRemovePossible}"  />
            </StackPanel>
        </AppBar>
    </Page.BottomAppBar>
    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="{Binding Path=HelloMessage}" 
            Style="{StaticResource    HeaderTextStyle}" 
            HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</Page>

MainPage.xaml.cs

using System.ComponentModel; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; namespace HelloWindows { /// <summary> /// An empty page that can be used on its own or navigated to within a Frame. /// </summary> public sealed partial class MainPage : Page, INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private const string BASE_MESSAGE = "Hello Windows"; public MainPage() { this.InitializeComponent(); HelloMessage = setMessge(_exlamationPointCount); this.DataContext = this; } private void RaisePropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public string HelloMessage { get; set ; } /// <summary> /// Invoked when this page is about to be displayed in a Frame. /// </summary> /// <param name="e">Event data that describes how this page was reached. /// The Parameter /// property is typically used to configure the page.</param> protected override void OnNavigatedTo(NavigationEventArgs e) { } private int _exlamationPointCount = 0; private static string setMessge(int exlamationPointCount) { if (exlamationPointCount > 0) { return BASE_MESSAGE + new string('!', exlamationPointCount); } else { return BASE_MESSAGE; } } private void addPoint_Click(object sender, RoutedEventArgs e) { HelloMessage = setMessge(++_exlamationPointCount); RaisePropertyChanged("HelloMessage"); RaisePropertyChanged("IsRemovePossible"); } private void removePoint_Click(object sender, RoutedEventArgs e) { if (_exlamationPointCount >= 1) { HelloMessage = setMessge(--_exlamationPointCount); RaisePropertyChanged("HelloMessage"); RaisePropertyChanged("IsRemovePossible"); } } // Make it possible to disable Remove Point button when there // is nothing left to remove public bool IsRemovePossible { get { return _exlamationPointCount > 0; } } } }

My Brain Dead Simple Windows RT App: The Series

Sunday, March 03, 2013

Brain Dead Simple Windows RT App

Brain Dead Simple Windows RT App Part 1

This article creates a really simple base app that I will use as a starting point for at least 1 other blog post (I’m holding this one until the first one is done).

In this series I will site design standards and then violate them. My intention is to justify why you need to learn how to use things like App Bars and Charms. At the same time, I don’t want to spend too many words trying to make everything UX correct. Microsoft has committed thousands of bits to the internet about Windows 8 UX standards on MSDN and various blogs.

Build the Brain Dead Simple App

  1. Create a new Visual C# Windows Store “Blank App (XAML)”
  2. Call it “HelloWindows”
  3. Open MainPage.xaml
  4. Within the bottom most Grid, add a text block with the Text of “Hello Windows”



I added a little style and now the grid XAML looks like this:

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <TextBlock Text="Hello Windows" 
        Style="{StaticResource HeaderTextStyle}"
        HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>

Add Binding for Future Proofiness

I know that I will need to make my app a little more interactive. With this in mind, I’m going to add some really simple binding code and XAML plumbing so I can separate this from the later posts.

public sealed partial class MainPage : Page, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private const string BASE_MESSAGE = "Hello Windows";
    public MainPage()
    {
        this.InitializeComponent();

        HelloMessage = setMessge(ExlamationPointCount);
        this.DataContext = this;
    }

    private void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
AND XAML
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <TextBlock Text="{Binding Path=HelloMessage}" 
        Style="{StaticResource HeaderTextStyle}" />
</Grid>

My Brain Dead Simple Windows RT App: The Series

Tuesday, February 26, 2013

I want Half View in Windows 8

Windows 8 has this mode that they call "Snap View" where an app takes 10% of the screen and another one takes the other 90%. This is cool because it allows me to work with two apps at the same time (sort of). However I sometimes like to compare things where one app isn’t that much more important than the other. For this I would request half screen where each app would get 50%.

This may be an edge case, but I like to compare the WinRT version of common apps like Kindle and Evernote with their Classic Windows versions. With two monitors I could do this, but if with just my laptop, no way. I would also like to compare two WinRT apps or even compare the data of two different apps.

Monday, February 11, 2013

My New Surface RT

This weekend I finally got my Windows RT tablet. It is a 64 GB Surface. I am using it right now to write this very blog entry.

ARM vs Intel

Originally, I was going to hold out for a Surface Pro (and I nearly made it), but I began to think about: 1) I need to be able to test my stuff on an ARM device. 2) I need to think in a Metro way (since I don’t work for the Empire, I can still use that term), I need to find a Metro app to solve whatever problem I need to solve. 3) Most of the desktop stuff I need to do require more screen area; 10 inches is not enough space for Visual Studio. 4) Besides, I’m a cheapskate.

I am running Windows 8 on my elderly HP laptop. I plan on getting a new laptop with touch much later this year; it’ll probably be cheaper than this Surface RT.

Office

I know that Window 8 is somewhat experimental. Still, I’m disappointed that there is no Metro, er, Modern App version of Office. I know that would be a big task and that Microsoft will eventually get around to it, it would be cool to see how such a big and important app migrated to the Modern World. Is there an Office worthy app out there that belongs on the Tablet.

Tuesday, January 29, 2013

WinRT CS vs JS: Grids

C# XAML

In XAML, a grid is pretty straight forward. Within the Grid tag, you define the rows and column in RowDefinitions and ColumnDefinitions tags. Below the definitions, you place the controls that will reside in the Grid, you assign them to cells and control cell spans with Row. attributes.

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="1*"/>
        <RowDefinition Height="1*"/>
        <RowDefinition Height="1*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*"/>
        <ColumnDefinition Width="1*"/>
        <ColumnDefinition Width="1*"/>
    </Grid.ColumnDefinitions>
    <TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">Title</TextBlock>
    <TextBlock Grid.Row="1" Grid.Column="0">2, 1</TextBlock>
    <TextBlock Grid.Row="1" Grid.Column="1">2, 2</TextBlock>
    <TextBlock Grid.Row="1" Grid.Column="2">2, 3</TextBlock>
    <TextBlock Grid.Row="2" Grid.Column="0">3, 1</TextBlock>
    <TextBlock Grid.Row="2" Grid.Column="1">3, 2</TextBlock>
    <TextBlock Grid.Row="2" Grid.Column="2">3, 3</TextBlock>
</Grid>

This is straight forward; the WinJS examples will attempt to match this layout.

JavaScript HTML


In WinJS, a grid is achieved using an IE 10 specific version of the CSS Grid Layout. Since this is CSS, you can select HTML elements using id or class selectors, you can even use inline styles. In this example, I will mix in all three. Basically you:

Create a style for the grid, in that style you need to tell it to display as a grid with a display attribute with the value -ms-grid.

Define the columns with a -ms-grid-columns property (“1fr” means 1 fraction value, behaves like 1* in XAML, see table below).

Define the rows with a -ms-grid-rows property.

You can assign an HTML element to a row with a -ms-grid-row and to a column with a -ms-grid-column. I have been playing with the idea of creating a class for each row and column/

With this in mind, I created the following CSS (put in css/default.css, if you want to do this yourself):

#MainGrid {
    display: -ms-grid;
    -ms-grid-columns: 1fr 1fr 1fr;
    -ms-grid-rows: 1fr 1fr 1fr;
    height: 100%; /* make it big, so we can see it */
}
.Col01 {
    -ms-grid-column: 1;
}
.Col02 {
    -ms-grid-column: 2;
}
.Col03 {
    -ms-grid-column: 3;
}
.Row01 {
    -ms-grid-row: 1;
}
.Row02 {
    -ms-grid-row: 2;
}
.Row03 {
    -ms-grid-row: 3;
}

OK, so you have some styles, but you can’t see styles. You need some HTML markup to receive the styles.

At this early stage in my WInJS development, it makes sense to me to style the main grid using an ID selector, so I’m calling the main grid div “MainGrid”. Each grid is going to be unique.

For row and column assignment I am using the ColXX and RowXX classes. To me is as easy to read as XAML’s Grid.Row=”0” and you can avoid creating ids for every cell in every cell in your application.

And I’m using the inline style on the first row to force it to span the 3 columns. I was debating using a class called “ColSpan03” but this gave me the opportunity to demonstrate an inline style.

With all this in mind, here’s the HTML for my grid (put in the body of default.html, if you are playing along at home):

<div id="MainGrid" >
    <div class="Col01 Row01" style="-ms-grid-column-span: 3">Title</div>
    <div class="Col01 Row02">2, 1</div>
    <div class="Col02 Row02">2, 2</div>
    <div class="Col03 Row02">2, 3</div>
    <div class="Col01 Row03">3, 1</div>
    <div class="Col02 Row03">3, 2</div>
    <div class="Col03 Row03">3, 3</div>
</div>

Comparing units in Row and Column Definitions


Here is a list of the various units that can be used to define the sized of rows and columns.


Purpose XAML WinJS Notes
Fractional Units * so 1 fractional unit would be “1*”, 2 would be 2* and so on fr so 1 fractional unit would be “1fr”, 2 would be “2fr” and so on  
Auto Sizing “auto” “auto” Although they are the same keyword, they behave slightly differently,
WinJS is more willing to wrap text and XAML is more likely to scroll
Percent Not supported % so fifty percent would be “50%” For XAML, you could use Fractional Units that add up to 100
Pixels Just the number, so 20 pixels would be “20” px, so 20 pixels would be 20px  
Inches Not supported in  
Centimeters Not supported cm  
Millimeters Not supported mm  
Points Not supported pt