Input Validation – UI Exceptions & Model Validation Errors

Note:  I rewrote this article on 12/29/2008 after speaking with my great friend and MVVM Master Josh Smith.  I changed the ViewBase class to call a method on the ViewModelBase class instead of my original method of communicating from the View to the ViewModel using an ICommand.  This is a cleaner and simpler solution.  Originally I was trying to have a very decoupled solution.  In my zeal to be pure, I overlooked the obvious and simpler approach.

The purpose of this article is to explain the necessity for monitoring binding exceptions caught in the UI that he data model would not be aware of.  This material while explained in the context of M-V-VM, still applies to all WPF business applications.

The Problem

A TextBox in the View is bound to an integer property on the Model.  That integer property has an associated IDataErrorInfo validation rule that requires that the property value be between 0 and 100.

If the user enters a value less than 0 or greater than 100, the Model will report an error that the binding pipeline will pickup and if the TextBox has a Validation.ErrorTemplate, will display some error message to the user.

Now the user enters 5b and tabs to the next field.  Since 5b is not an integer, the binding pipeline will get an exception when attempting to set the property value on the Model since there is a type mismatch.

Now the TextBox.Text property on the View is 5b, the Model does not know that the View has an invalid value and if the Model’s current value is within the limits of any applied validation rules, the Model thinks it’s valid.

So you can see that under these circumstances there is a disconnect between the View and Model.  It is this disconnect that I would like to address and provide a solution for.

Other Solutions I Considered

Purchase or author UI controls that do not allow invalid input.  It is very easy to author a Numeric only TextBox in WPF.  However, when you get to the Date TextBox, I think things get a little more complex and can end up with the same disconnect I explained above. 

I’ve never liked masked input controls and users really don’t like them either.  Besides, why can’t my Date TextBox work like the Outlook 2007 Date Input Control?  Play around with Outlook’s, you’ll be surprised what you can enter and it just figures it out for you.  For example, gives these a try:  mon, fri, 3, 24.  Also I want to bring back the ” + “, ” – ” and ” . ” keys for date entry. 

Fancy control aside, it’s possible for a control like this to have invalid input that does not translate to a date and you end up with the same disconnect; View is invalid and the Model is valid.

As a person who writes lots of blog and Code Project articles, I can’t use a 3rd party control because developers would need to purchase the 3rd party control license in order to compile my projects on their systems.  So that is a non-starter.  I also want readers to be able to take my code and use it at their work if they so desired.  Not taking a dependency on a 3rd party solution makes this much simpler for readers and me too.

Josh Smith has also come up with a very good solution that you can read in this blog post, Using a ViewModel to Provide Meaningful Validation Error Messages.  I actually really like Josh’s solution as it provides a great solution including reformatting and data type conversion error messages.  My only push back was having to abstract all the properties of the Model on the ViewModel.  I have run into some scenarios were doing this has its own side effects that I didn’t want to have to code around.

This is also the beauty of M-V-VM.  While the pattern has some specific layers and components, implementation details can differ, sometimes a good bit but yield the same solid results.  I would encourage all WPF LOB developers to look at many different M-V-VM implementations and draw your own conclusions.  I came to mine after spending 3 weeks memory profiling many M-V-VM applications with different implementations of the M-V-VM pattern.  The patterns shared here, use the minimum amount of resources and do not have memory leak problems.

My Requirements

  • Solution must be simple
  • Solution must be reusable and easy to implement in many applications
  • Solution must be rock solid and impossible for the user to get into an invalid or disconnected state as described above
  • Solution must not require that controls on Views implement anything outside of the normal Data Binding properties
  • Solution must provide data for an error listing in the View when the programmer needs it
  • Solution must provide a simple technique for the ViewModel to know if the View and Model are valid for the purposes of View notification and Save Command enabling and disabling

Solution Architecture

The CustomerViewModel exposes the Customer Model as a property.  You will discover that this entire solution is contained in two base classes, ViewModelBase and ViewBase.  ViewModels and Views that derive from these classes won’t have to deal with this code at all.  The solution just works.  At Microsoft we say, “IJW.”  (it just works)

During the CustomerViewModel lifetime, if the Customer objects needs to be reloaded, for example after a record is inserted or updated to the database, a re-read of the record in the database is required.  After the record is reloaded, the CustomerViewModel can raise the PropertyChanged event for the Customer property and the View will automatically refresh itself.  Implementing M-V-VM in this fashion makes for a clean approach that does not require the reloading of the View or ViewModel when the data changes, just the reloading of the Model in necessary.

CustomerViewModelCusstomerModel

The ViewModelBase class exposes three methods for working with data binding exceptions in the UI, AddUIValidationError, RemoveUIValidationError and ClearUIValidationErrors.  The first two are public methods called by the below ViewBase.ExceptionValidationErrorHandler.  The ClearUIValidationErrors is a protected method that the deriving ViewModel can call as required; for example when the Model exposed by the ViewModel is reloaded and the UIValidationErrors need to be cleared.

The UIValidationErrorCount property returns the number of UIValidationErrors.  Use this property when checking for the presence of UIValidationErrors.

The UIValidationErrorUserMessages property is what the View data binds to when displaying a list of UIValidationErrors to the user.  It returns one string with the property name and message, “has invalid entry” for each UIValidationError.

The UIValidationErrorFullMessages property is for demonstration purposes for this application only.  Please remove this from any other application as it serves no purpose other than for this demo application.

CustomerViewViewBaseNew

When the user enters a value in the UI that causes an exception to be thrown by the data binding pipeline, the ExceptionValidationErrorHandler gets the exception.  The ExceptionValidationErrorHandler actually gets called when the exception is initially throw and when the exception is cleared.  Getting notification of exceptions being added and removed makes tracking these very simple.  As stated above the ExceptionValidationErrorHandler calls either the ViewModelBase.AddUIValidationError or ViewModelBase.RemoveUIValidationError method when an exception is added or removed.

UIValidationError Sequence Diagram

Thank Josh Smith for the great suggestion to put this complex sequence of events in a Sequence Diagram.

ErrorEventSequanceDiagram

In addition to the UIValidationErrorUserMessages property the UIValidationErrorCount property has property changed notification that the UI can data bind to.

While these seems a little complex, application View’s and ViewModels simply need to derive from these or similar classes to get the functionality for free.

Application

The test bench application allows has two sections.  The top Customer section is the form for data entry.  The UI and ViewModel Errors section displays UI Validation Exceptions and validation rule violations from the Model.

The Full Name field is a required entry from 1 to 30 characters long.

The Satisfaction Level field has a validation rule on the model requiring values to be from 0 to 100.

The red ” * ” indicate either a validation rule violation or that an exception was thrown when assigning a value to the Model property.

The Save button will only be enabled when the View and Model are both valid and without exceptions.

ValidationApplication

In the above image you can see that the Satisfaction Level is invalid.  It’s not between 0 and 100.  This is an IDataErrorInfo validation error.  This is an example of a normal data entry validation rule violation and technique for displaying the condition to the user.

The Retired field, Nullable(Of Date) has an exception.  “a11-12″ is not a valid date.  The Model knows nothing about the invalid Retired TextBox, but since the ViewModel as been informed of the invalid TextBox.Text property, the ViewModel will not allow the user to save any data until the exceptions have all been corrected and the Model validation rules all pass.

I’m showing both the UIValidationErrorUserMessages and UIValidationErrorFullMessages properties.  Notice how the UIValidationErrorUserMessages displays a user friendly version of the UIValidationError.

Future Usage

In future MVVM example applications, I’ll demonstrate using these classes in a real world application.  For now, understanding that these conditions can exist is very important and that we need to handle them in our applications.

Video

This video link requires Microsoft Silverlight 1.0 or 2.0.  If you do not have it, you will be prompted to install it when you click one of the links.  After the short installation is completed, close the browser window that you did the install in and re-click the video you want to watch.   You can also download it here. Windows XP or Vista required.

  Input Validation For M-V-VM

Download

After downloading the below file, you must rename the file from .DOC to .ZIP.  This is a requirement of WordPress.com

Updated 12/28/2008  Download Source (26KB)

Hope you have a great day!

Just a grain of sand on the worlds beaches.

37 Responses to Input Validation – UI Exceptions & Model Validation Errors

  1. ricke44654 says:

    Karl, I stumbled across this post while searching for ways to handle data binding errors. This post really helped me a lot! I compared your solution to Josh Smith’s solution that you mentioned and fell on your way because it fit my situation a little better. I combined your ideas here with a great post by Paul Stovell on CodeProject (http://www.codeproject.com/KB/cs/DelegateBusinessObjects.aspx) to create a rules engine that is centralized and works very well in my library application I’m writing. Thanks a lot for this post, it expanded my knowledge of data binding and helped me solve my last nagging data binding issue. Keep up the great work!

  2. mindsprober says:

    MVVM is great for separation of concerns. Karl you did a great job in explaining it. Here is another way of attaching a view to the view-model. just sharing another perspective to the viewers :) – Shams (http://geekscafe.net)


    <!–

    –>

  3. mindsprober says:

    I think the XAML code was truncated… sorry! I dont know how to post it. – Shams

  4. dashingsidds says:

    Hi Karl the above mentioned post is very nice.

    I am having some problem in understanding the source code as it is written in vb and i am not very good in the same.

    If you Can please post the same source code in C# then it would be of gr8 help.

    Thanks in advance.

    Regards,

    Samar

  5. nareshbhatia says:

    Thanks for the great article Karl! I have a quick question for you. I am using your C# code along with Prism. Specifically I am using Prism’s DelegateCommand instead of your RelayCommand. For some reason, when validations fail in my application the Save button is not disabled. I put a breakpoint in my CanExecute() method and it is not hit after changing a field (even though PropertyChanged events are generated). In your sample app this method is being called almost every second. What might be the difference?

    Thanks,
    Naresh

    • Naresh,

      The Prism DelegateCommand does not subscribe to CommandManager.RequerySuggested, which is why I don’t use it. DelegateCommand leaves it up to the developer for calling CanExecute.

      RelayCommand subscribes to CommandManager.RequerySuggested if you pass the Predicate in the ctor. For WPF, I always use RelayCommand so I get this behavior for free.

      Cheers,

      Karl

  6. [...] like a lot of additional work. I additionally began looking into Karl Shifflett's implementation here, but I can't seem to capture the routed event I would anticipate when putting this code into the [...]

  7. [...] article describes a solution which is much easier to implement in that most of the code is contained in two [...]

  8. evgenyn says:

    It’s a very nice implementation! But is there something like this for silverlight?

  9. jmix90 says:

    Hello,

    Thank you for this great article !

    I think validation can be the most difficult and less documented thing about WPF/MVVM.

    Jonathan ANTOINE
    http://blog.lexique-du-net.com
    http://wpf-france.fr

  10. Hai,
    Thanks for your great article…
    here i have one clarification..
    i want to allow empty value also in Textbox… my TextBox is binding with Openingbalance Property..
    openingbalance datatype is Decimal… this field also allows nullable… here suppose i entered value 5.50 then clear all value after changing focus.. that time also Exception return…

    how to solve this?
    could you tell me some ideas?

  11. Hello,
    Thanks for your nice article…. suppose if i allow null to satisfication level ..after enter some values in this textbox finally clear all values in Textbox then press tab(that means lost focus) that time also exception throws…

    how to solve this problem?
    could you tell me some ideas?

    thank you….

  12. rafaelbc says:

    Hi Karl,

    I know this is somewhat an old post, but it is undoubtedly a great one. There are very few solutions around providing a way to couple the validation to the view-model, so this one is of great value. Josh Smith’s solution is easy to implement and keep track of everything, but it makes me uncomfortable to have all my properties exposed as strings. Kinds of makes no sense if you think of a unit testing perspective, for example – you’d never be able to benefit on strong typing when testing the view model.

    However, Josh’s solution has a definitive plus: you don’t need to work with value (or type) converters on the XAML side. And that is something I don’t see how your solution can cope with.

    What if I want to bind my TextBox to an IPAddress property? Since IPAddress is not provided with a TypeConverter out-of-box, you have two alternatives: either writing an IValueConverter or writing a custom TypeConverter.

    The IValueConverter.ConvertBack() method which is responsible for converting the string in the TextBox to an IPAddress instance cannot throw exceptions as documented in the Remarks section of http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.convertback(v=VS.90).aspx. That said, it should return a DependencyProperty.UnsetValue instead, which then leads to the fact that the setter of my IPAddress property is never called, hence leaving the validation method in the IDataErrorInfo call to be executed in the previous value of my IPAddress property, which possibly is the valid (considering you loaded it from the model, for example).

    Implementing a custom TypeConverter is not much different than that. The good point is that you can throw an exception in its ConvertTo() method, which can be caught in the UI if your Binding.ValidatesOnExceptions is set to true. But then, the setter of the property is not called again, and you run into the same scenario when using IValueConverter.

    So basically the idea is: how can the view-model know it is not in a valid state anymore, if its properties were not set?

    Sorry for the lengthy email, but I guess that is something worth a thought :-)

    Any ideas? Thanks in advance!

    (By the way, I’m using .NET 3.5)

    • Karl says:

      My Ocean framework has property validators on the model that determines if the value is valid, so no type converters required. In the case of an IP address, the property would be a string and the validator would ensure the user input matches the required rule. I try to keep my code as simple as possible.

      Best,

      Karl

  13. mariocatch says:

    Hello Karl, Happy Holidays to you :)

    Quick question;
    I have a View with some TextBoxes bound to custom validation rules.
    I have a Button on my View bound to a SaveCommand.

    I’d like my SaveCommand’s CanExecute (CanSave) to only return true if no validation errors exist within my View.
    Since my View is the one binding to validation rules, my ViewModel has no idea if any exist.

    Is there a simple way to tap into this knowledge that my View has? I’d rather not write a trigger vs every TextBox on my View, and would rather see if I can just add validation errors to a collection somewhere that my ViewModel could bind to perhaps.

    (I’ve also posted this question at http://social.msdn.microsoft.com/Forums/en/wpf/thread/6e464e8f-a7a0-4655-8647-7bf154b1e136 , but it seemed related to your post here.

    Thanks,
    -Mario

  14. Sonali Patil says:

    Hi, This post is really good to know. Just have one question

    My CustomerModel contains ID and Name properties
    CustomerModel List Observable Collection is bound to UI combo box list as ItemsSource
    CustomerModel object is bound to Selected Item of Combo Box

    In this case, if i want to check for validation, Adding IDataErrorInfo is not usable in Model

    Your solution looks perfect in these cases

    The only thing is i want to know how can i add this validation if i use your approach.

    • Karl says:

      The validation is done in the model. My solution adds the UI exceptions to the model validation errors the View Models knows about.

      Karl

  15. Hi, Karl. Thank you for this great code but I’ve noted there is a problem when I type an invalid value for “SatisfactionLevel” and then I type a value to cause a conversion error, the UIValidationErrorUserMessages property returns a correct error string,but in a second call it retuns an empty string and the form keep showing only the model validation error and not the conversion error. I’m not an experimented WPF programmer and would like you or someone else to spare a thought for this problem. Thanks one more time.

  16. Karl, the problem I’ve reported above occurs only in the Net Framework 3.5.1. After I’ve changed to Net Framework 4.0, all goes right.

  17. Ben Way says:

    In the intro of your article you mention that you are trying to solve the disconnect between the View and the Model. However, when I run your solution and enter 5b into the UI Retired field, I get an error message but the view textbox still shows 5b. The textbox has one value and the model has a completely different value, isn’t there still a mismatch?

    I am trying to find a solution whereby the user would get a message that the value they entered was invalid, for whatever reason, but the textbox and the model values stay in sync. This means that the textbox would be reset to the previously valid model value. Do you know if this is possible?

    • Karl says:

      Ben,

      What you are seeing is the purpose of the article; to catch this condition and handle it.

      5b will not work for an Integer field. So the UI shows 5b and the model is whatever value is was.

      In this case, you can’t and do not want them in sync. Just account for the exception in the UI and inform the VM that there is an exception in the UI and not allow the model to be saved.

      Karl

  18. Terrific article. (In fact all of your articles are indispensible for anybody trying to do anything in wpf). I have been looking for this solution all over the place and it was great to find such a nice and easy solution without having to change the types of my viewmodel properties.(aka Josh Smith solution)

    I wanted to be able to change an unbound property in my viewmodel when an exception hit. What I did was change the methods in the viewmodelbase to be overideable.

    Public Overridable Sub AddUIValidationError(ByVal e As UIValidationError)
    etc…

    Then in my viewmodel class where all the view properties are – I added the overrides method and have complete access to any properties in the current business object and then just call the MyBase.AddUIValidationError(e) to continue processing.

    Public Overrides Sub AddUIValidationError(ByVal e As UIValidationError)
    Me.IHaveErrors = True
    MyBase.AddUIValidationError(e)
    End Sub

    In the ViewBase class I changed the call to the AddUIValidationError by getting my viewmodel class by using the binding .Dataitem property which gives me my viewmodel.

    objBindingExpression.DataItem.AddUIValidationError(New UIValidationError(strDataItemName, strPropertyName, sb.ToString))

    I set the same logic for the RemoveUIValidationError and the my property gets set and unset along with the rest of your logic.

    The one problem I had is I had to set option strict off in the viewbase class because the following code:
    objBindingExpression.DataItem would throw a late binding error with option strict on.

    I like to know if what I did really makes sense or am I missing something and heading for problems ahead.

    Thanks for all your articles,
    George

    • Karl says:

      George,

      Below is the code I’m using today, some slight changes. My abstract class is called EditFormViewBase. I’ve been using this code for years, never even look at it, it just works.

      Best to you,

      Karl

      public EditFormViewBase() {
      this.Loaded += EditFormViewBase_Loaded;
      this.Unloaded += (s, e) => this.RemoveHandler(Validation.ErrorEvent, new RoutedEventHandler(ExceptionValidationErrorHandler));
      }

      void EditFormViewBase_Loaded(Object sender, RoutedEventArgs e) {
      this.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(ExceptionValidationErrorHandler), true);
      }

      Boolean IsExceptionValidationRule(String name) {
      // this is required because ConversionValidationRule is not public. What’s up with that?
      return name.EndsWith(“ExceptionValidationRule”) || name.EndsWith(“ConversionValidationRule”);
      }

      void ExceptionValidationErrorHandler(Object sender, RoutedEventArgs e) {
      var args = (ValidationErrorEventArgs)e;

      if (IsExceptionValidationRule(args.Error.RuleInError.ToString())) {
      var editFormViewModelBase = this.DataContext as EditFormViewModelBase;

      if (editFormViewModelBase != null) {
      //we only want to work with validation errors that are Exceptions because the business object has already recorded the business rule violations using IDataErrorInfo.
      var bindingExpression = (BindingExpression)args.Error.BindingInError;
      var dataItemName = bindingExpression.DataItem.ToString();
      var propertyName = bindingExpression.ParentBinding.Path.Path;
      var sb = new StringBuilder(1024);

      foreach (ValidationError ve in Validation.GetErrors((DependencyObject)args.OriginalSource)) {
      if (IsExceptionValidationRule(ve.RuleInError.ToString())) {
      sb.AppendFormat(“{0} has error “, propertyName);

      if (ve.Exception == null || ve.Exception.InnerException == null) {
      sb.AppendLine(ve.ErrorContent.ToString());
      } else {
      sb.AppendLine(ve.Exception.InnerException.Message);
      }
      }
      }

      if (args.Action == ValidationErrorEventAction.Added) {
      editFormViewModelBase.AddViewValidationError(new ViewValidationError(dataItemName, propertyName, sb.ToString()));
      } else if (args.Action == ValidationErrorEventAction.Removed) {
      editFormViewModelBase.RemoveViewValidationError(new ViewValidationError(dataItemName, propertyName, sb.ToString()));
      } else {
      //this can only happen if the .NET Framework changes. Better to put a sanity check in now that have a very hard to find bug later.
      throw new OverflowException(String.Format(“Action value was not programmed: {0}”, args.Action));
      }
      }
      }
      }

  19. Karl,

    Public Class ViewBase
    Inherits UserControl
    ‘This Code comes from Karl Shifflet on input validation

    #Region ” Declarations ”
    Private _objErrorEventRoutedEventHandler As RoutedEventHandler
    Private objBindingExpression As BindingExpression

    Private Function IsExceptionValidationRule(ByVal name As [String]) As [Boolean]
    ‘ this is required because ConversionValidationRule is not public. What’s up with that?
    Return name.EndsWith(“ExceptionValidationRule”) OrElse name.EndsWith(“ConversionValidationRule”)
    End Function
    #End Region

    #Region ” Methods ”
    Private Sub ExceptionValidationErrorHandler(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim args As System.Windows.Controls.ValidationErrorEventArgs = DirectCast(e, System.Windows.Controls.ValidationErrorEventArgs)

    If IsExceptionValidationRule(args.[Error].RuleInError.ToString()) Then
    Dim objViewModelBase As BaseViewModel = TryCast(Me.DataContext, BaseViewModel)
    If objViewModelBase IsNot Nothing Then
    ‘we only want to work with validation errors that are Exceptions because the business object
    ‘ has already recorded the business rule violations using IDataErrorInfo.
    objBindingExpression = DirectCast(args.Error.BindingInError, System.Windows.Data.BindingExpression)
    Dim strDataItemName As String = objBindingExpression.DataItem.ToString
    Dim strPropertyName As String = objBindingExpression.ParentBinding.Path.Path
    Dim sb As New System.Text.StringBuilder(1024)
    For Each objVE As ValidationError In System.Windows.Controls.Validation.GetErrors(DirectCast(args.OriginalSource, DependencyObject))
    If IsExceptionValidationRule(objVE.RuleInError.ToString()) Then
    sb.AppendFormat(“{0} has error “, strPropertyName)
    If objVE.Exception Is Nothing OrElse objVE.Exception.InnerException Is Nothing Then
    sb.AppendLine(objVE.ErrorContent.ToString)
    Else
    sb.AppendLine(objVE.Exception.InnerException.Message)
    End If
    End If
    Next
    If args.Action = ValidationErrorEventAction.Added Then
    ‘new code
    SetMyProperty(“IHaveErrors”, True)
    objViewModelBase.AddUIValidationError(New UIValidationError(strDataItemName, strPropertyName, sb.ToString))
    ElseIf args.Action = ValidationErrorEventAction.Removed Then
    ‘new code
    SetMyProperty(“IHaveErrors”, False)
    objViewModelBase.RemoveUIValidationError(New UIValidationError(strDataItemName, strPropertyName, sb.ToString))
    Else
    ‘this can only happen if the .NET Framework changes. Better to put a sanity check in now that have a very hard to find bug later.
    Throw New ArgumentOutOfRangeException(“Action”, args.Action, “Action value was not programmed.”)
    End If
    End If
    End If
    End Sub

    Private Sub SetMyProperty(ByVal [Property] As String, ByVal [Value] As Boolean)
    ‘New code to set proerty value in viewmodel
    If objBindingExpression IsNot Nothing Then
    Dim sourceItem = objBindingExpression.DataItem
    If sourceItem IsNot Nothing Then
    sourceItem.[GetType]().GetProperty([Property]).SetValue(sourceItem, [Value], Nothing)
    End If
    End If
    End Sub

    Private Sub UserControlBase_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
    ‘this adds a form level handler and will listen for each control that has the NotifyOnValidationError=True and a ValidationError occurs.
    _objErrorEventRoutedEventHandler = New RoutedEventHandler(AddressOf ExceptionValidationErrorHandler)
    Me.AddHandler(System.Windows.Controls.Validation.ErrorEvent, _objErrorEventRoutedEventHandler, True)
    End Sub

    Private Sub UserControlBase_Unloaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Unloaded
    Me.RemoveHandler(System.Windows.Controls.Validation.ErrorEvent, _objErrorEventRoutedEventHandler)
    _objErrorEventRoutedEventHandler = Nothing
    End Sub
    #End Region
    End Class

  20. Sorry about that it got posted before I finished. Thank-you for your response.
    I was disecting your code and notices the only change you made was to add the ISExceptionValidationRule to trap conversionValidation rules.

    I was not happy with my previous post where i had to set option strict off to access my view model from your validation code. My goal was to set a property in my view model (“ihaveerrors” – boolean property) when a validation error occured.

    I came up with a short addition to your code to accomplish this. I added a small sub procedure to set my property called “SetMyProperty”. I get a reference to my viewmodel detail with:

    sourceItem.[GetType]().GetProperty([Property]).SetValue(sourceItem, [Value], Nothing)

    This will set and unset my property and does not require the option strict off.

    Thanks again,
    George

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 241 other followers