PDC 2009 Recap PodCast

Wednesday, January 27, 2010 8:54:34 PM (GMT Standard Time, UTC+00:00)

You can hear about some thoughts on PDC 2009 over on Microsoft Developer Evangelist Jeff Brand’s blog.  He sat down with Rocky Lhotka, Scott Davis and myself in December and we talked about our thoughts on PDC.

http://www.slickthought.net/post/2010/01/07/Spaghetti-Code-Recaps-PDC-2009.aspx

Building Loosely Coupled Applications – V2

Wednesday, January 27, 2010 8:29:58 PM (GMT Standard Time, UTC+00:00)

I gave this presentation in St. Louis and Minneapolis last year.  I updated it and gave it to the .NET User Group in Mankato, MN last night.  It now includes a section on MEF (Managed Extensions Framework).

You can download the updated deck and slides below.

Code and Deck

What’s new in Silverlight 4

Wednesday, January 27, 2010 8:20:07 PM (GMT Standard Time, UTC+00:00)

Below is the presentation that I gave to the Twin City Silverlight Users Group last month.  I had issues with my laptop that I got from PDC… which also happened to be the laptop that I used for the presentation so it took me a while to recover the files.  Attached is the presentation.

ListView with AutoColumns

Monday, December 07, 2009 10:00:10 PM (GMT Standard Time, UTC+00:00)

When you are prototyping it is nice to get things up and running quickly.  The other day I was using the DataGrid to prototype some work I am doing and it just so happened the result sets were rather large.  I like the fact that the DataGrid can dynamically create columns on the fly… but with large working sets of data, it takes longer to render then a GridView.

With that, I created a simple mechanism that will auto generate the GridView for you through reflection. Set the returning GridView to the View property on the ListView. Here are the helper calls:

public class GridViewHelper
   {
       /// <summary>
       /// Auto generates a GridView based on public properties in an object.
       /// </summary>
       /// <typeparam name="T"></typeparam>
       /// <returns></returns>
       public static GridView AutoGridView<T>()
       {
           GridView view = new GridView();
 
           foreach (PropertyInfo info in typeof(T).GetProperties())
           {
               GridViewColumn gridViewColumn = GenerateGridViewColumn(info.Name);
               view.Columns.Add(gridViewColumn);
           }
 
           return view;
       }
 
       /// <summary>
       /// Auto generates a GridView based on public properties in an instance of an object.
       /// </summary>
       /// <param name="instance">The instance.</param>
       /// <returns></returns>
       public static GridView AutoGridView(object instance)
       {
           GridView view = new GridView();
 
           foreach (PropertyInfo info in instance.GetType().GetProperties())
           {
               GridViewColumn gridViewColumn = GenerateGridViewColumn(info.Name);
               view.Columns.Add(gridViewColumn);
           }
 
           return view;
       }
 
       /// <summary>
       /// Generates the grid view column based on a property name
       /// </summary>
       /// <param name="propName">Name of the prop.</param>
       /// <returns></returns>
       private static GridViewColumn GenerateGridViewColumn(string propName)
       {
           GridViewColumn gridViewColumn = new GridViewColumn();
           gridViewColumn.Header = propName;
           gridViewColumn.DisplayMemberBinding = new Binding(propName);
           return gridViewColumn;
       }
 
       /// <summary>
       /// Define the Property Names you want to show in the Grid.
       /// </summary>
       /// <typeparam name="T"></typeparam>
       /// <param name="columns">The columns.</param>
       /// <returns></returns>
       public static GridView AutoGridView(params string[] columns)
       {
           GridView view = new GridView();
 
           foreach (string propName in columns)
           {
               GridViewColumn gridViewColumn = GenerateGridViewColumn(propName);
               view.Columns.Add(gridViewColumn);
           }
 
           return view;
       }
   }

Microsoft Application Architecture Guide – Second Edition available for download.

Tuesday, December 01, 2009 2:09:34 AM (GMT Standard Time, UTC+00:00)

Ran across this today looking for some other things on DotNet.

http://blogs.msdn.com/microsoft_press/archive/2009/11/22/new-book-microsoft-application-architecture-guide-second-edition.aspx

WPF Instigator Code Released on CodePlex

Friday, November 06, 2009 10:57:08 PM (GMT Standard Time, UTC+00:00)

You can get the source code to Instigator at:

http://instigator.codeplex.com/

Using DispatchTimer to help in UI Behavior

Wednesday, October 21, 2009 12:49:49 AM (GMT Daylight Time, UTC+01:00)

I have ran into this problem a number of times developing UI.  You have business logic that needs to execute when a user is done entering some piece of data or criteria.  The business logic may be complicated and takes longer then what is considered an acceptable threshold (somewhere around 3 seconds). 

Your first thought might be to use the TextChanged, SelectionChanged or KeyUp events to detect change in the targeted control and run the business logic… but after you have implemented the approach you find out that the logic is just too expensive and the UI appears locked or sluggish.  The LostFocus event doesn’t work well either… it doesn’t get fired in some situations (clicking on a toolbar or selecting a menu).  

The approach that I have used both in WinForms and WPF development is to monitor the TextChanged event and when event has gone dormant for a specified duration, run the business logic. The key is not to wait an extended period of time to run the logic, but rather execute the logic at a tight enough interval that the application appears responsive after the user is has completed their data entry.

This is what the code does.

In the constructor we setup a DispatchTimer to fire at a default interval and subscribe to the TextChange event of our target control.

public ExecuteOnDormant(TextBox ctl, Action action)
{
    _control = ctl;
    _action = action;
    _dormantTimer = new DispatcherTimer();
 
    _defaultTimeout = new TimeSpan(0, 0, 0, 0, _timeOut);
 
    if (_timeOut == 0)
        _dormantTimer.IsEnabled = false;
    else
    {
        _dormantTimer.Interval = _defaultTimeout;
        _dormantTimer.IsEnabled = false;
        _dormantTimer.Tick += new EventHandler(RunBusinessLogic);
 
        //assumging that it is only a textbox we are watching... if we want to make this more generic... then add a  to KeyUp or SelectionChanged
        _control.TextChanged += new TextChangedEventHandler(ctl_TextChanged);
    }
}

The handler for the TextChange event then resets the DispatchTimer… this allows the user to complete typing the value before complex business logic is run.

/// <summary>
/// Handles the TextChanged event of the control that we are monitoring to run business logic on.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.Windows.Controls.TextChangedEventArgs"/> instance containing the event data.</param>
private void ctl_TextChanged(object sender, TextChangedEventArgs e)
{
    ProcessActivity();
}
 
/// <summary>
/// Processes the activity(keyboard and mouse) in the shell to ensure that it stays active and does not fire the 
/// IdleTimeOut event.
/// </summary>
private void ProcessActivity()
{
    //reset the timer, the control has changed.
    _dormantTimer.IsEnabled = false;
    _dormantTimer.Interval = _defaultTimeout;
 
    //now enable the timer, as we want it to fire when it times out.
    _dormantTimer.IsEnabled = true;
}

When the user has stopped typing long enough for the interval to expire the business logic is executed.  To make this class usable across different controls we use an Action delegate to define the business logic.

private void RunBusinessLogic(object sender, EventArgs e)
       {
           //disable the timer, so it doesn't continue to run the business logic
           _dormantTimer.IsEnabled = false;
           Dispatcher.CurrentDispatcher.InvokeOnUIThread(_action);
       }

The business logic definition looks like this:

public partial class Window1 : Window
    {
        private ExecuteOnDormant _dormantWatcher;
        private Random _randomVal = new Random();
        public Window1()
        {
            InitializeComponent();
 
            _dormantWatcher = new ExecuteOnDormant(txtCriteria, ExecuteComplexBusinessLogic(txtCriteria));
        }
 
        private Action ExecuteComplexBusinessLogic(TextBox control)
        {
           return  () =>
                       {
                           Mouse.SetCursor(Cursors.Wait);
                           
                           //run complex business logic...
                           int val = _randomVal.Next(1,3);
 
                           //make it seem like a long time
                           Thread.Sleep(1000);
                           
                           //give the rich feedback on whether the item passed validation
                           control.Background = (val == 1) ? Brushes.LightGreen : Brushes.Salmon;
 
                           Mouse.SetCursor(Cursors.None);
                       };
        }
    }

You will notice that it uses a extension method off of the CurrentDispatcher called InvokeOnUIThread.  This method ensures that the business logic is executed in the correct thread context.  Below is the implementation for the extension method.

/// <summary>
/// Invokes on the UI thread if necessary.
/// this.Dispatcher.InvokeIfNecessary(() =>
/// {
        //do something that might need to be invoked
/// });
/// </summary>
/// <param name="dispatcher">The dispatcher.</param>
/// <param name="action">The action.</param>
public static void InvokeOnUIThread(this Dispatcher dispatcher, Action action)
{
    if (Thread.CurrentThread == dispatcher.Thread)
    {
        action();
    }
    else
    {
        dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate { action(); });
    }
}

You can download the demo project.

Instigator – Application Launcher

Saturday, September 26, 2009 3:22:12 AM (GMT Daylight Time, UTC+01:00)

I am pretty dependent on Enso for helping me navigate not only my file system, but links related to doing everyday tasks in my job (Bug Tracking, Time Reporting, Requirements, Design Documents, coding… and the list goes on). I recently received a new laptop(with all of the AD policies you could want)… and the build doesn’t seem to want to allow me to run Enso, so I wrote a replacement for it. Basically it is another launcher application.

What I don’t like about some of the other launcher applications is that you have do 2 or 3 steps before you can launch your application (plus their UI is out-dated). Windows 7 has some search capabilities similar to Vista ( but  better) in that you can use the Windows key to drop down the Start menu and begin typing for the application or file that you are looking for.  This works well… but I don’t like the fact that the list is indiscriment… in other words I didn’t ask for everything to be included in the search… I just wanted targeted thing I use all of the time. 

With Enso, launching applications was much easier… a matter of holding down the caps lock while you typed a key word… a little weird but it worked.  It pulled program files and short-cuts to websites and most importantly application or file short-cuts that you added.  It wasn’t a laundry list like we get in Windows.

I call my replacement for Enso… Instigator.  It uses shortcuts stored in folders you identify to launch your applications. It is a single portable executable that requires the 3.5 .NET Framework.  The UI is shown below:

clip_image001

Configuring Instigator

  1. Download the application zip:
  2. Copy the contents to where you would like.
  3. Edit the config file so Instigator knows where to find your short-cuts.  An example config file is shown below. Add a DiscoveryPath to the config of where you would like Instigator to look for short-cuts. Remove any DiscoveryPaths that you do not want Instigator to load.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name ="InstigatorSettings"
             type ="Sysknowlogy.Tool.OS.XmlSerializerSectionHandler, Sysknowlogy.Instigator"/>
  </configSections>
 
  <InstigatorSettings type ="Sysknowlogy.Tool.OS.InstigatorSettings , Sysknowlogy.Instigator">
    <DiscoveryPaths>
      <DiscoveryPath location=".\shortcuts\" />
      <DiscoveryPath location="C:\Documents and Settings\sbraun\Desktop\OpenCommands" />
    </DiscoveryPaths>
  </InstigatorSettings>
</configuration>

Using Instigator

  1. Start the executable, after the splash screen disappears the application is loaded.
  2. Use Ctl-Win to bring up the search window. Right now this is not configurable, it will be in later releases.
  3. This should bring up the application with the list of short-cuts that you defined in your discovery paths.
  4. Begin typing to limit the list of items to launch.  The search uses a contains to filter… as you type it will eliminate your options.
  5. Once the items fore color you are looking for is highlighted, hit enter.

Known Issues

  • Focus set to the filter textbox sometimes gets botched up… typically when Visual Studio is open. VS likes to steal focus a lot. This doesn’t happen a great deal, but does occasionally. To fix it, you will need to click in the filtering textbox with your mouse.
  • If the application process cannot be started, Instigator does not notify you that if failed to launch the application.  It just won’t do anything.

Reporting errors / problems
While in the launch filter textbox, type in “report” which will result in a “report a problem or bug” in the drop down.  Select that item and hit enter.  This will launch the default mail client and allow you to mail be a bug.

Getting Started - Automation of WPF UI

Wednesday, September 23, 2009 3:21:43 AM (GMT Daylight Time, UTC+01:00)

So you ask your self… “Where do I start”… I have been tasked with finding out how we can automate our WPF application for testing or just to drive development unit testing quicker.  You have done some searches and stumbled upon this blog, but you have so many questions.

How does it work from a high level…
The core concept is that we should be able to automate our application via a single API across different platforms (Winforms, WPF, ASP.NET).  Microsoft has spent a great deal of time defining UI interaction patterns, so these can be abstracted out in a API that will allow us to drive the UI from code.  This abstracted API is defined in patterns.  There is a list of the patterns found for accessing controls:

http://msdn.microsoft.com/en-us/library/ms750574.aspx

and here is how to use the patterns to access properties on the element:

http://msdn.microsoft.com/en-us/library/ms752056.aspx

How do I drive the UI from a API standpoint…
First you create some sort of driver application… like a console application. This application then uses code like this to create the process:

Process p = null;
p = Process.Start(@"C:\temp\UI.Shell.exe");

Once you have the process created you can pass the MainWindowHandle property of the process class to the Automation API.  Another approach is to pass in the string found in the titlebar of the application and allow the automation API to search for the window.  From there you use a variety of identifiers to reference the different controls.  One approach is to use the AutomationID, which maps to the xaml controls x:name property.  You can also use the ClassName to identify controls, which then maps to the .NET type of the control.  If you are not sure of a controls AutomationID or ClassName you can use UISpy.exe (comes with the Windows SDK) to find out how you can reference the control.

Here is a code sample to give you an idea of how this all comes together.  The following sample starts a WPF application and then completes a login view and triggers the login from a button.

Console.WriteLine("\nBegin WPF UIAutomation test run\n");
                Console.WriteLine("Launching the application");
                Process p = null;
                p = Process.Start(@"C:\temp\bin\wpfApplication.exe");
 
                int ct = 0;
                do
                {
                    Console.WriteLine("Looking for application process. . . ");
                    ++ct;
                    Thread.Sleep(10);
                }
                while (p == null && ct < 50);
 
                if (p == null)
                    throw new Exception("Failed to find application process");
                else
                    Console.WriteLine("Found application process");
 
                Console.WriteLine("\nGetting Desktop");
                AutomationElement aeDesktop = null;
                aeDesktop = AutomationElement.RootElement;
                if (aeDesktop == null)
                    throw new Exception("Unable to get Desktop");
                else
                    Console.WriteLine("Found Desktop\n");
 
 
                Console.WriteLine("\nLooking for application main window. . . ");
                Thread.Sleep(5000);
                AutomationElement application = AutomationElement.FromHandle(p.MainWindowHandle);
               
                Console.WriteLine("\nCompleting controls. . . ");
                AutomationElement loginView = application.FindFirst(TreeScope.Children,
                     new PropertyCondition(AutomationElement.ClassNameProperty,
                     "LoginView"));
 
                AutomationElement loginPart = loginView.FindFirst(TreeScope.Children,
                    new PropertyCondition(AutomationElement.ClassNameProperty,
                    "LoginPart"));
 
                AutomationElement txtUserName = loginPart.FindFirst(TreeScope.Children,
                    new PropertyCondition(AutomationElement.AutomationIdProperty, 
                    "username"));
                AutomationElement txtPassword = loginPart.FindFirst(TreeScope.Children,
                   new PropertyCondition(AutomationElement.AutomationIdProperty,
                   "password"));
 
                Console.WriteLine("\nSetting input to a030601");
                ValuePattern vptxtUserName = (ValuePattern)txtUserName.GetCurrentPattern(ValuePattern.Pattern);
                vptxtUserName.SetValue("testuser");
                ValuePattern vptxtPassword = (ValuePattern)txtPassword.GetCurrentPattern(ValuePattern.Pattern);
                vptxtPassword.SetValue("p@ssword1");
 
 
                AutomationElement cmdLogin = loginPart.FindFirst(TreeScope.Children,
                   new PropertyCondition(AutomationElement.AutomationIdProperty, "authenticationButton"));
 
                Console.WriteLine("\nClicking on Compute button");
                InvokePattern ipLoginCmd =
                  (InvokePattern)cmdLogin.GetCurrentPattern(
                  InvokePattern.Pattern);
                ipLoginCmd.Invoke();

Are there any good examples that show me how to drive the UI…
There are a number of articles that I found… but the most simplistic and straight forward is an article that was published in MSDN magazine back in March of 2009. Automating UI Tests in WPF Applications

Some more interesting information about WPF and automation for improving the quality of your application can be found in the WPF Application Quality Guide.

.Net Best Practices Event

Wednesday, April 01, 2009 3:32:59 AM (GMT Daylight Time, UTC+01:00)

Here is the deck and code samples I presented for the .NET Best Practices event that was hosted in St. Louis, Missouri on March 24th and in Bloomington, Mn on March 31st.

Building Loosely Coupled Applications

DeckAndCode.zip (2.58 MB)