WPF DataBinding with slow loading ItemSource

by matt 12. July 2011 21:38

I discovered an interesting WPF databinding issue recently.  Say we have this simple example WPF form for editing a customer:

image

<Label Content="First Name:" Grid.Row="0" Grid.Column="0" />
<TextBlock Grid.Row="0" Grid.Column="1" MinWidth="125" Text="{Binding SelectedCustomer.FirstName}"/>
<Label Content="Last Name:" Grid.Row="1" Grid.Column="0" />
<TextBlock Grid.Row="1" Grid.Column="1" MinWidth="125" Text="{Binding SelectedCustomer.LastName}"/>
<Label Content="Contact Flag:" Grid.Row="2" Grid.Column="0" />
<ComboBox Grid.Row="2" Grid.Column="1"
     Margin="5"
     ItemsSource="{Binding ContactFlags}"
     DisplayMemberPath="Value"
     SelectedValuePath="Key"
     SelectedValue="{Binding SelectedCustomer.ContactFlag}"
        />

In particular we are interested in the Contact Flag combobox.  We have a viewmodel with a SelectedCustomer (which for the sake of this post is just being instantiated in the constructor, but would probably come from a DB, etc), however the Contact Flag comes from a list of key value pairs, being a code and a description.

image

Say for example though, that the list of contact flags comes from a slow source such as a web service.  As you can see above the databinding fails.  Seems obvious, the list of items hasn’t loaded, so the item isn’t able to display in the list.  However the comboxbox has now pushed a null value back to the customer:

image

Double Whammy!  Not only is the item not bound, but if this customer had a previous value for Contact Flag, it has now been wiped out and if a user hits the OK button to save, it would be lost for good.

So in our viewmodel instead of doing this:

SelectedCustomer = new Customer
              {
                  FirstName = "John",
                  LastName = "Smith",
                  ContactFlag = "e"
              };

              FlagService fs = new FlagService();
              fs.GetContactFlagsAsync(OnFlagsReceived);

we would want to save off the customer in a private variable and then set it once the callback for the list (OnFlagsReceived) has happened.  (Another option would be to simply wait to retrieve the customer until the callback if possible).

By doing so we then set the binding only after the values in the combobox exist and get the outcome we want:

private void OnFlagsReceived(Dictionary<string,string> flags)
      {
          ContactFlags.AddRange(flags);

          SelectedCustomer = _customerToSave;
      }

A simple change, but an important difference.  Not only did we correct the binding issue, but we also kept the domain object from accidentally getting updated and saved some poor unsuspecting end user from accidentally calling a difficult tech savvy customer who prefers email. Winking smile

You can download the sample code for this project here.

Tags:

MVVM and closing a View from the ViewModel

by matt 17. February 2011 20:35

One of the common questions when working with MVVM is how do you close a view from the viewmodel?

The answer is usually send a message to the view from the viewmodel, but this ends up with an ugly message registration in the view’s code behind.  For Blend users, custom behaviors are a great way to avoid this ugliness.  (I think all you really need to make this work is the System.Windows.Interactivity.dll assembly which I’m pretty sure is in the Blend SDK, but having actual Blend will make attaching behaviors, etc. a lot easier).

In this example I will be using MVVM Light and its associated Messenger/Message classes, but the same concepts should work in your favorite MVVM framework as well.

First create your custom behavior, which registers for the message in OnAttached:

class CloseWindowBehavior : Behavior<Window>
    {

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

            Messenger.Default.Register<CloseWindowMessage>(this.AssociatedObject,
                   m =>
                   {
                        this.AssociatedObject.DialogResult = m.Content;
                        this.AssociatedObject.Close();
                   }
                );

        }

    }

Note that I have created a custom MVVM Light message type CloseWindowMessage:

class CloseWindowMessage : GenericMessage<bool?> 
   {

       public CloseWindowMessage(bool? dialogResult)
           :base (dialogResult) { }
       
       public CloseWindowMessage(object sender, bool? dialogResult)
           :base(sender,dialogResult) { }
       
       public CloseWindowMessage(object sender, object target, bool? dialogResult)
           : base(sender, target, dialogResult) { }

   }

I prefer this since it allows me to send along the DialogResult, however you could use the normal NotificationMessage (Sorry not the best link, but currently all I can find) with a “CloseWindow” message if you aren’t concerned with that.

Now if you attach this behavior to your window, then in your viewmodel all you have to do is:

Messenger.Default.Send<CloseWindowMessage, MainWindow>(new CloseWindowMessage(true));

Note, be sure you specify the target when using this method.  If all your windows have this behavior and you simply blast this message, you will be in for a surprise. ;)

Bonus coverage:

For those using MVVM Light, here is a behavior for its DialogMessage:

public class DialogMessageBehavior : Behavior<Window>
  {

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

          Messenger.Default.Register<DialogMessage>(this.AssociatedObject,
              (dm) => MessageBox.Show(this.AssociatedObject, dm.Content, dm.Caption, dm.Button, dm.Icon));
              

      }

  }

Tags: , , ,

WPF

Custom Schema and ICustomTypeDescriptor

by matt 3. December 2010 22:07

In our project we support custom schema on our tables.  We support both extending the domain tables and allow the creation of completely ad hoc tables.  Currently in the project to display a list of these records we use the custom schema framework which returns a wrapper object and usually then build a datatable on the client side out of the results and bind a grid to that.  Recently I discover ICustomTypeDescriptor which allows an object to provide its own type information.

The default databinding implementation uses reflection to get the properties and values for those properties from an object.  The ICustomTypeDescriptor interface allows an object to step in and provide this information dynamically.

So say for example I have a custom “ad hoc” table (I use quotes here because in the case of this post its actually just the Employee table from the Chinook database, but we’ll suspend disbelief and say its ad hoc. 

I then have a custom field schema implementation, again for the sake of the post I have a very naïve implementation that just reads a datareader into a dictionary.  Obviously a real implementation would probably need metadata, etc., for the post I’m keeping it simple.

So I run a simple select statement and end up with a list of CustomSchemaTableRecord objects:

List<CustomSchemaTableRecord> records = new List<CustomSchemaTableRecord>();

           using (SqlConnection connection = new SqlConnection(Properties.Settings.Default.ConnectionString))
           {
               SqlCommand command = new SqlCommand(
                 "SELECT * FROM Employee",
                 connection);

               connection.Open();

               SqlDataReader reader = command.ExecuteReader();

               while (reader.Read())
               {
                   records.Add(new CustomSchemaTableRecord(reader));
               }

               reader.Close();
           }

           dataGridView1.DataSource = records;

Which as you can see really is just a dictionary internally (again naïve implementation for simplicity):

image

However when I databind these records to the datagrid in the last line I get:

image

Nothing…great post right?

Why do we get nothing?  CustomSchemaTableRecord has no properties.  In fact it has basically no external interface at all.  All it has is a constructor and a private dictionary to store its values in.  No external interface means nothing returned to reflection and so nothing to databind to.

But, if we implement ICustomTypeDescriptor on CustomSchemaTableRecord (this is snipped to just the interesting parts, see the link above to the MSDN documentation to see all the required methods):

 

#region ICustomTypeDescriptor Members


      public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
      {
          List<PropertyDescriptor> properties = new List<PropertyDescriptor>();

          foreach (var kvp in values)
          {

              properties.Add(new CustomSchemaTypePropertyDescriptor(kvp.Key, kvp.Value.GetType()));

          }

          return new PropertyDescriptorCollection(properties.ToArray());

      }

Note: This code is not checking for nulls, etc. its probably not safe to copy and paste directly…

Here I return a PropertyDescriptorCollectionPropertyDescriptor is an abstract class that I implemented with my CustomSchemaTypePropertyDescriptor class (again snipped for brevity, see link above etc., etc.):

class CustomSchemaTypePropertyDescriptor : PropertyDescriptor
   {

       private Type type;

       public CustomSchemaTypePropertyDescriptor(string key, Type type)
           :base(key,null)
       {
           this.type = type;
       }


       public override object GetValue(object component)
       {
           CustomSchemaTableRecord record = component as CustomSchemaTableRecord;

           return record.GetValueForKey(this.Name);
       }
         

Again here null checks, etc…

For the keen eyed, you’ll notice when GetValue is called I am calling the GetValueForKey method on my CustomSchemaTableRecord, which is simply this:

public object GetValueForKey(string key)
      {
          return values[key];
      }

Now that I have implemented ICustomTypeDescriptor to provide my list of dynamic properties and created my custom PropertyDescriptor to provide the value back to the databinding when asked, when we rerun the app we now get:

image

Since this implementation just works against my ad hoc custom field framework, I can simply change my selection criteria to say “SELECT * FROM Customer” and I get:

image

Perfect databinding for an table with dynamic schema.

A little snag I ran into along the way was that databinding (or maybe just the grid itself) seems to be picky about the list of items, it must be a list that implements ITypedList.  At first I was just using an array and it did not work.  However once I switched to a generic List<T>, all was right.

In our project we seldom databind directly to the domain objects that support custom schema.  However, this new implementation will decrease the amount of code in the ad hoc table implementation.  No need any longer to build ugly in memory datatables to databind to.  Just take the custom schema records that are returned out of the business logic and implement ICustomTypeDescriptor directly on them, or write a wrapper to implement it and  hand them off as the datasource, that simple.

Tags:

Visual Studio Brace Matching

by matt 2. October 2010 17:25

I’ve noticed that since I installed VS 2010 I now longer had brace matching, the handy feature where if you put your cursor on one brace, VS will automatically highlight the matching one.  Then I realized that I had installed the Visual Studio power tools, which has line highlighting like this:

image

Its really handy since it quickly draws your eye to the line that the cursor is currently on.  No more hunting around the screen to find it.  However as you can see above there is no brace matching.  It finally dawned on me that the simple problem is that the default color for both the line highlighting and brace matching is the same.

A quick trip to Tools –> Options –> Fonts and Colors and a change to the Brace Matching (Rectangle) color and I was able to have the best of both worlds:

image

Tags:

The Command Pattern and Extension Methods

by matt 27. September 2010 05:10

When using the Command Pattern recently to implement Undo in an application, I ran into an interesting issue.  When implementing the pattern more than likely there will end up being some object with a method that looks like this:

void ApplyCommand(ICommand command);

Its not hard to understand, you need some instance of an object that implements ICommand.  You pass it in and then the object will execute the command.  However sometimes finding those (especially when buried 3 or 4 namespaces deep in a third party library) can be a hassle. 

For example, let’s assume we have a simple Document object (in this case, just the Interface for it) that looks like this:

interface IDocument
    {
        void Save(string fileName);
        bool AutoSave { get; set; }
        int WordCount { get; }
        int PageCount { get; }
        
    }

Eventually the request to support Undo (and probably Redo) comes in for the application.  We come up with a list of commands that we want to support Undo for, such as Changing font size, indenting a large area of text, etc.  ICommand is implemented for each of them and the above ApplyCommand method is added to the IDocument interface.

However in the consuming code from now on whenever someone needs to change the font they now have to create a FontSizeCommand and then pass that to the ApplyCommand method, which will internally store the command in its undo stack and execute the command on itself.  It would be nicer if the consuming code could simply call:

document.FontSize(12);

We could pollute the interface with a new convenience method for each of these commands, but that would get out of hand extremely quickly (as well make the interface a huge hassle to implement on another type).  Instead, this is a great opportunity to use extension methods.  Simply define extension methods in a class in the same namespace as the IDocument interface itself and then anytime you add a using statement for it, you will also get the extension methods along with it automatically:

public static class IDocumentExtensions
    {

        public static void FontSize(this IDocument document, int fontSize)
        {
            ICommand command = new FontSizeCommand(fontSize);
            document.ApplyCommand(command);
        }

        public static void Indent(this IDocument document, string textBlock)
        {
            IndentCommand command = new IndentCommand(textBlock);
            document.ApplyCommand(command);
        }

    }

and you will see:

image

Writing extension methods on your own code always seems a little strange.  When you think about it, you own the code, you could just edit the class directly.  However many times providing your own extension methods can help provide an easy to use outward facing API but allow for clean implementation.

My note about a third party library above is actually what lead me to using this code myself.  The 3rd party library had a nice Command Pattern implementation, but the various commands were spread out all over the namespaces (of which there are many).  I always end up have to resort to Intellisense spelunking to find what I want.  Next time you’re writing a Command based, or really any separated API, consider providing extension methods along with it, the consuming code (and developer) will thank you.

Tags: ,

Extension Methods | Design Patterns

Fun with StructureMap

by matt 17. August 2010 18:56

At work we use Linq2SQL and loosely support multi-tenancy.  As a result our UnitOfWork takes a DataContext/Repository strategy instead of taking a DataContext directly (actually there are both an IRepository & IDataContext interface that somewhat hide the L2S datacontext).  A somewhat simplified example looks like this:

interface IRepository
    {
        IQueryable<T> SelectAll<T>();
        void Add<T>(T entity);
        void Remove<T>(T entity);
        void SubmitChanges();
    }


    interface IUnitOfWork
    {
        void SubmitChanges();

    }

    public class UnitOfWork : IUnitOfWork
    {
        IRepository repository; 

        public UnitOfWork(Func<IRepository> repositoryStrategy)
        {
            this.repository = repositoryStrategy();
        }
        
        public void SubmitChanges()
        {
            throw new NotImplementedException();
        }

    }

As you can see instead of taking an IRepository directly the UnitOfWork actually takes a Func<IRepository> which allows us to change out the datacontext per tenant (to be honest its probably more complicated and fragile than it needs to be, once there are more unit tests surrounding it, I may swap it all out).

Speaking of Unit Tests I’ve been playing with StructureMap to make some of the setup of my tests a little simpler.  When I want to test our classes that hold the business logic a lot startup code has to be written. 

I wrote some Factory methods that basically do this:

IRepository repository = new FakeRepository();

           IUnitOfWork unitOfWork = new UnitOfWork(() => repository);

           AccountService service = new AccountService(unitOfWork);

The fun thing here is that if the ObjectFactory is initialized correctly I can just use the it as the Repository strategy:

ObjectFactory.Initialize(x => 
          {
              x.For<IRepository>().Use<FakeRepository>();
              x.For<IUnitOfWork>().Use<UnitOfWork>()
                  .Ctor<Func<IRepository>>("repositoryStrategy")
                  .Is(() => ObjectFactory.GetInstance<IRepository>());
                  
          });

Now I can use this like so:

AccountService service = ObjectFactory.GetInstance<AccountService>();

and the service gets a valid UnitOfWork:

image

In production you would need to be very careful of your objects lifetime, for example in this example the L2S datacontext would probably never get disposed.  Since I’m just using this to spin up my classes in my Unit Tests, that’s probably not a huge concern.  YMMV.

That aside I thought the interesting thing here was the ability to call the ObjectFactory itself again to complete the strategy and get the needed object.  I wasn’t sure if it would work, but after a little playing I was able to get it working.  Now that this important task is out of the way I can actually write more tests ;)

Tags: , , ,

Unit Testing | IoC

Lost Visual Studio Icon

by matt 12. August 2010 16:32

At some point on my machine Visual Studio 2010 lost its icon.  It wasn’t a huge deal, just an annoyance since every time I would look down at the taskbar instead of seeing the VS icon I would see the generic Windows “document” icon.

I would end up opening several copies of VS not realizing I already had it open.  I also keep it pinned to my taskbar and would forget that the default blob down there was VS so I would hunt all over the start menu to open a new instance. 

Finally today I found the problem, somehow I had associated .csproj files with Notepad.  I’m not sure how it happened and I’m not sure why it broke my VS icon (and actually I can’t seem to recreate it anymore) but once I fixed the settings to match below and chose VS as the default for the file type, all was well.

image

Tags:

Logging to Trace, Verbose, etc. with log4net

by matt 14. July 2010 05:53

The default ILog interface for log4net only presents forward 7 logging levels (ALL, DEBUG, INFO, WARN, ERROR, FATAL, OFF”).  In a few projects I have for a long time wanted to a level between INFO and DEBUG.  There is information that I would like to log for my purposes, but for others it is simply clutter.

In researching how to write a custom level I started poking around Level.cs and noticed toward the bottom (around line 500) there are already a large number of default logging levels define, its jus that as mentioned above the default ILog interface doesn’t present them forward.

I started considering writing my own ILog implementation but then it hit me, extension methods to the rescue:

public static class ILogExtentions
    {
        private static readonly log4net.ILog log = 
            log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        
        public static void Trace(this ILog log, string message, Exception exception)
        {
            log.Logger.Log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType, 
                log4net.Core.Level.Trace, message, exception);
        }

        public static void Trace(this ILog log, string message)
        {
            log.Trace(message, null);
        }

        public static void Verbose(this ILog log, string message, Exception exception)
        {
            log.Logger.Log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType, 
                log4net.Core.Level.Verbose, message, exception);
        }

        public static void Verbose(this ILog log, string message)
        {
            log.Verbose(message, null);
        }



    }

These extension methods should probably actually go on ILogger, (which as you can see above is where the actual Log method is) but since I always use the default ILog implementation this makes calling the methods feel more natural.

Now I can simply call log.Trace or log.Verbose and get log output.  So instead of having a level between DEBUG and INFO, I have just started logging my stuff at a level below debug.  Now the technical users can review the DEBUG log without having to see my very fine level messages.

As I mentioned there are a large number of additional levels defined that the same methods could easily be implemented for.

image

Note: Don’t forget to update your log4net config to turn on these additional levels.  I spent a while thinking these methods weren’t working until I figured out I just hadn’t turned them on. Enjoy!

Tags:

log4net

Snippets

by matt 5. June 2010 09:01

A few months back Chad did a presentation for our local .Net users group (Mailing List) on Snippets (by the way, he will be presenting it at SharePoint Saturday Ozarks).  I hadn’t really played with snippets much before then, but since I have found them to be a pretty big time saver.  I thought there’s no reason to keep them to myself, so from time to I’ll post the interesting ones here.

During the presentation he suggested storing your snippets in an online store so you can share them across locations.  So I have put mine into a Dropbox folder, added those into my VS instances at home and work (Tools –> Code Snippets Manager) and now my snippets are synchronized across my machines.

(Note some of these include long line of unbroken code with will probably not render very well in the browser, you’ll be better off just cutting and pasting them into VS.)

So with out further ado:

We use Log4Net in a couple of projects at work, and I always end up looking up the  line of code to initialize the logger, now a simple “log4net” [TAB][TAB] does the job:

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <Header>
    <Title>Log4Net</Title>
    <Author>Matt Lowrance</Author>
    <Shortcut>log4net</Shortcut>
    <Description>Inserts the log4net logging information </Description>
    <SnippetTypes>
      <SnippetType>Expansion</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>
    <Code Language="CSharp">
      <![CDATA[private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);$end$]]>
    </Code>
  </Snippet>
</CodeSnippet>
private static readonly log4net.ILog log = 
            log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <Header>
    <Title>Console ENTER to Continue</Title>
    <Author>Matt Lowrance</Author>
    <Shortcut>entercontinue</Shortcut>
    <Description>Prints "Please press ENTER to continue" and reads a line to provide a pause</Description>
    <SnippetTypes>
      <SnippetType>Expansion</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>
    <Code Language="CSharp">
      <![CDATA[Console.WriteLine("Press ENTER to continue");
            Console.ReadLine();]]>
    </Code>
  </Snippet>
</CodeSnippet>


This one is just a simple helper when writing a command line tool:

Console.WriteLine("Press ENTER to continue");
           Console.ReadLine();

I’ve been writing some integration tests lately and found that a large number of them were tests to ensure a proper exception was thrown under the correct circumstances:

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <Header>
    <Title>Expected Exception</Title>
    <Author>Matt Lowrance</Author>
    <Shortcut>ee</Shortcut>
    <Description>Creates an ExpectedException attribute for Unit Tests</Description>
    <SnippetTypes>
      <SnippetType>Expansion</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>
    <Declarations>
      <Literal>
        <ID>TypeOfException</ID>
        <Default>ArgumentNullException</Default>
      </Literal>
    </Declarations>
    <Code Language="CSharp">
      <![CDATA[[ExpectedException(typeof($TypeOfException$))]$end$]]>
      
    </Code>
  </Snippet>
</CodeSnippet>

This outputs the test attribute:

[ExpectedException(typeof(ArgumentNullException))]

Similar to one above VS come with cw for “Console.WriteLine();”, so I wrote and simple “cr” for “Console.ReadLine();”:

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <Header>
    <Title>Console.ReadLine</Title>
    <Author>Matthew Lowrance</Author>
    <Shortcut>cr</Shortcut>
    <Description>Outputs Console.Readling()</Description>
    <SnippetTypes>
      <SnippetType>Expansion</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>
    <Code Language="CSharp">
      <![CDATA[Console.ReadLine();]]>
    </Code>
  </Snippet>
</CodeSnippet>

Last, and luckily I haven’t actually ever had to use this one, but I just thought it would be a fun one to have available:

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <Header>
    <Title>Abandon All Hope</Title>
    <Author>Matt Lowrance</Author>
    <Shortcut>aah</Shortcut>
    <Description>Displays an ASCII art skull and Cross Bones with the quote "Abandon all hope, all ye who enter here"</Description>
    <SnippetTypes>
      <SnippetType>Expansion</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>
    <Code Language="CSharp">
      <![CDATA[
/*************************************************************
 *                                                           *
 *   .=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-.      *
 *   |                     ______                     |      *
 *   |                  .-"      "-.                  |      *
 *   |                 /            \                 |      *
 *   |     _          |              |          _     |      *
 *   |    ( \         |,  .-.  .-.  ,|         / )    |      *
 *   |     > "=._     | )(__/  \__)( |     _.=" <     |      *
 *   |    (_/"=._"=._ |/     /\     \| _.="_.="\_)    |      *
 *   |           "=._"(_     ^^     _)"_.="           |      *
 *   |               "=\__|IIIIII|__/="               |      *
 *   |              _.="| \IIIIII/ |"=._              |      *
 *   |    _     _.="_.="\          /"=._"=._     _    |      *
 *   |   ( \_.="_.="     `--------`     "=._"=._/ )   |      *
 *   |    > _.="                            "=._ <    |      *
 *   |   (_/                                    \_)   |      *
 *   |                                                |      *
 *   '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-='      *
 *                                                           *
 *        ABANDON ALL HOPE, ALL YE WHO ENTER HERE            *
 *************************************************************/]]>
    </Code>
  </Snippet>
</CodeSnippet>

Tags:

Unit Test Keyboard Bindings

by matt 2. June 2010 20:19

I have been writing some integration tests lately in preparation for a refactoring effort to make our code more Unit Test friendly.  The code was not originally written with any kind of testing in mind, and as a result there are a large number of dependencies (including the Linq 2 Sql datacontext) that are currently very hard to test.

Since most of these test are fairly straight forward they usually pass on the first run.  The default keyboard binding for Run-> Tests in the Current Context and Debug –> Tests in the Current Context are the same: Ctril+R,T.  This means that each time a test is run the full debug environment is spun up, which is slow when you are fairly sure the test is going to pass.

On the other hand the “Run Tests” in the context menu runs much more quickly:

image

 

I have lived in fear of the F1 key for a long time so I thought this would be a good opportunity to kill two birds with one stone. 

Remapping Visual Studio keyboard shortcuts is pretty straight forward.  First follow the directions in the link above to remove the default F1 binding (Tools –> Options, Keyboard,  Search for “Help” then remove the Help.F1Help command).  The search for “RunTests” and choose EditorContextMenus.CodeWindow.RunTests from the list.  Below in the “Press shortcut keys” textbox press the F1 (or any other key combination you would want to use) and click “Assign”:

image

Now F1 will run the tests in the current context without needing the context menu (you can see it mapped in the screenshot below):

image

I have actually found this to be a pretty big time saver.  Since on these integration tests I don’t often need to debug and I run them fairly often just one at a time, using this short cut saves 5-10 seconds for each test run over the debug version and keep my hands off the mouse (which is probably the largest time saver of all).

Tags:

About the Author

I am a software developer in Springfield, MO. I enjoy a large variety of software development related topics. I am always interested learning new technologies.

I am currently developing .Net Web & Windows applications in C#.

RecentPosts