# Thursday, 02 September 2010
A while back I posted a revision to my original default button sample that made it a bit easier to use, but there was still an issue...  If you invoke the button while the focus is still in a text box, any changes made to the text in the text box may not get pushed into the databinding source, since by default that happens when the text box loses focus.  I didn't come up with a good solution, but luckily somebody did. :)  I got the following revision from Glenn Orr, and this should solve the problem.  If you have any custom data entry controls, etc. you may have to add additional clauses to handle them, but this will work with text boxes for sure.

Change the OnKeyUp method to look like this...


private void OnKeyUp(object sender, KeyEventArgs arg)
{
	  if (arg.Key == Key.Enter)
			  if (peer != null)
			   {
					   if (sender is TextBox)
					  {
							   BindingExpression expression = (sender as TextBox).GetBindingExpression(TextBox.TextProperty);
							   expression.UpdateSource();
					  }
					  ((IInvokeProvider)peer).Invoke();
			  }
}
This will make sure that any changes get pushed into the databinding source before the button is invoked. Thanks Glenn!
Thursday, 02 September 2010 10:00:05 (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  | 
# Thursday, 11 June 2009

A month or so ago I posted on a solution for simulating “default button” semantics in a Silverlight app, meaning that if you are entering text in a text box and you hit the enter key, the “default button” for the “page” should be pressed.  Very natural for form entry, etc. 

An issue came up (discovered by John Papa) with the solution in a Prism app, because my solution depends on being able to find the “default” button in the visual tree using the FindName method.  That means that you have to be high enough up the visual tree to find the button, since it only works “down” the tree.  In a Prism app, it’s not necessarily clear where “high enough” might be.  Plus, because the solution requires unique names, and Prism modules may have nothing to do with one another, they may have duplicate names, etc.

Here’s a revision to the solution that doesn’t require unique names, and doesn’t require any static references that might interfere with proper garbage collection…

First, a new object called DefaultButtonHub that keeps track of the relationship between text boxes and buttons.  It also exposes an Attached Property that takes a DefaultButtonHub reference so we can hook up text boxes and buttons to the “hub” in XAML.

public class DefaultButtonHub
{
   ButtonAutomationPeer peer = null;

   private void Attach(DependencyObject source)
   {
       if (source is Button)
       {
           peer = new ButtonAutomationPeer(source as Button);
       }
       else if (source is TextBox)
       {
           TextBox tb = source as TextBox;
           tb.KeyUp += OnKeyUp;
       }
       else if (source is PasswordBox)
       {
           PasswordBox pb = source as PasswordBox;
           pb.KeyUp += OnKeyUp;
       }
   }

   private void OnKeyUp(object sender, KeyEventArgs arg)
   {
       if(arg.Key == Key.Enter)
           if (peer != null)
               ((IInvokeProvider)peer).Invoke();
   }

   public static DefaultButtonHub GetDefaultHub(DependencyObject obj)
   {
       return (DefaultButtonHub)obj.GetValue(DefaultHubProperty);
   }

   public static void SetDefaultHub(DependencyObject obj, DefaultButtonHub value)
   {
       obj.SetValue(DefaultHubProperty, value);
   }

   // Using a DependencyProperty as the backing store for DefaultHub.  This enables animation, styling, binding, etc...
   public static readonly DependencyProperty DefaultHubProperty =
       DependencyProperty.RegisterAttached("DefaultHub", typeof(DefaultButtonHub), typeof(DefaultButtonHub), new PropertyMetadata(OnHubAttach));

   private static void OnHubAttach(DependencyObject source, DependencyPropertyChangedEventArgs prop)
   {
       DefaultButtonHub hub = prop.NewValue as DefaultButtonHub;
       hub.Attach(source);
   }

}

Basically we’re expecting that both the text boxes and the button will register themselves with the “hub”.  If it’s a button that’s being registered, we wrap it in a ButtonAutomationPeer so we can “press” it later.  If it’s a text box, we hook up a KeyUp handler that will “press” the button if it’s there.  The requirement in the XAML is only marginally heavier than in my previous solution…we have to add a resource of type DefaultButtonHub, and point the button and text boxes at it using the {StaticResource} markup extension.

<UserControl x:Class="DefaultButton.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:my="clr-namespace:DefaultButton"
    Width="400" Height="300">
    <UserControl.Resources>
        <my:DefaultButtonHub x:Key="defaultHub"/>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBox x:Name="theText" Grid.Row="0"
                 my:DefaultButtonHub.DefaultHub="{StaticResource defaultHub}"/>
        <Button x:Name="theButton" Grid.Row="1" Content="Default"
                Click="theButton_Click" my:DefaultButtonHub.DefaultHub="{StaticResource defaultHub}"/>
    </Grid>
</UserControl>

Note that the new DefaultHub attached property is applied to both the text box and the button, each pointing the the single resource.  This way everything gets wired up property, there isn’t any problem with name resolution (aside from the usual resource name scoping) and everything will get cleaned up if the form needs to be GC’d.

Thursday, 11 June 2009 12:03:22 (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
# Tuesday, 02 June 2009

Most of the demos/samples I’ve looked at so far for RIA Services have started with a LINQ to SQL or ADO.NET Entity model and generated Domain Service classes from those.  I decided to start from something super simple (a POCO, if you will) and work up from there.  I started with a canonical  “Person” class

public partial class Person : INotifyPropertyChanged
{
   #region INotifyPropertyChanged Members

   public event PropertyChangedEventHandler PropertyChanged;

   #endregion

   protected virtual void Changed(string propertyName)
   {
       PropertyChangedEventHandler handler = PropertyChanged;
       if (handler != null)
       {
           handler(this, new PropertyChangedEventArgs(propertyName));
       }
   }

   private int _personId;
   public int PersonId
   {
       get
       {
           return _personId;
       }
       set
       {
           if (_personId != value)
           {
               _personId = value;
               Changed("PersonId");
           }
       }
   }

   private string _firstName;
   public string FirstName
   {
...
   }
   private string _lastName;
   public string LastName
   {
...
   }
   private System.DateTime _birthDate;
   public System.DateTime BirthDate
   {
...
   }
}

Nothing to see here.  It’s just a simple POCO that supports INotifyPropertyChanged for databinding.  Note that it’s a partial class…  The simplest path would be to add RIA Services attributes directly to these properties for things like data validation, but I wanted to try out all the features, so I split out the metadata into another file

[MetadataTypeAttribute(typeof(RiaServices.Web.Person.PersonMetadata))]
public partial class Person
{

   internal sealed class PersonMetadata
   {
       [Key]
       [Required]
       public int PersonId;

       [Required]
       [RegularExpression("[a-zA-z]*")]
       public string FirstName;

       [Required]
       [RegularExpression("[a-zA-z]*")]
       public string LastName;

       [Required]
       public DateTime BirthDate;
   }
}

This is kind of an interesting trick, and allows me to separate out all the RIA specific metadata from the original class definition.  This makes total sense when you look at the way they handle LINQ to SQL, for example.  In that case you already have Entity classes defined by the LINQ to SQL wizard, so this extra metadata class allows you to associate the right attributes without touching the (generated) LINQ to SQL classes.  Clever.  Notice that the metadata class uses fields, not properties, and just matches the names for the sake of simplicity.

In this case, the additional metadata defines data validation rules that get enforced both server and client side.  There are other attributes to enforcing string length and ranges. 

This all works because RIA Services generates “proxy” entity classes on the client side that are Silverlight compilable and also DataContracts (for serializing, which is cool…).  However, what happens if I have a calculated property that’s not just storage?  There’s a solution for that too, and it involves another piece of the partial class

public partial class Person
{
   [Shared]
   public int Age
   {
       get
       {
           this.Changed("Age");
           return Convert.ToInt32(Math.Floor((DateTime.Now - _birthDate).Days / 365.25));
       }
   }

}

This bit goes in a file called Person.shared.cs, and it will be copied to the client project and compiled there as well as on the server.  The [Shared] attribute marks the bits that need to be thus propagated.  Again, clever.  Of course, any such shared code has to compile in Silverlight.

The other piece of code I want to share (using the same method) is a custom validator.  In addition to the [Required] or [RegularExpression] attributes used above, you can register a custom validation routine that can examine the state of the entity as a whole.  The validation routine looks like this

[Shared]
public class PersonValidator
{
   public static bool IsPersonValid(Person p, ValidationContext context, out ValidationResult result)
   {
       bool valid = true;

       result = null;

       if (p.Age > 130)
           valid = false;

       if (!valid)
       {
           result = new ValidationResult("Birthdate is invalid, people can't be that old", new []{"BirthDate"});
       }

       return valid;

   }
}

That’s in a file called PersonValidator.shared.cs, so that it will be available client and server-side.  It’s associated with the Person entity with an additional attribute

[CustomValidation(typeof(PersonValidator), "IsPersonValid")]
[MetadataTypeAttribute(typeof(RiaServices.Web.Person.PersonMetadata))]
public partial class Person
...

With the Person entity all ready, I can expose it to the client by creating a new DomainService class with methods for Get, Insert, Update, Delete, etc.

[EnableClientAccess()]
public class PeopleDomainService : DomainService
{
   public IQueryable<Person> GetPersons()
   {

       return PeopleData.Persons.AsQueryable<Person>();
   }

   public IQueryable<Person> GetPerson(int personId)
   {
       return (from p in PeopleData.Persons
               where p.PersonId == personId
               select p).AsQueryable<Person>();
   }

   public void UpdatePerson(Person person)
   {
       Person oldP = (from p in PeopleData.Persons
                      where p.PersonId == person.PersonId
                      select p).FirstOrDefault();

       if (oldP != null)
       {
           PeopleData.Persons.Remove(oldP);
           PeopleData.Persons.Add(person);
       }
   }

   public void InsertPerson(Person person)
   {
       if (person.PersonId == 0)
       {
           int max = PeopleData.Persons.Max(p => p.PersonId);
           person.PersonId = max + 1;
       }

       PeopleData.Persons.Add(person);
   }

   public void DeletePerson(Person person)
   {
       Person oldP = (from p in PeopleData.Persons
                      where p.PersonId == person.PersonId
                      select p).FirstOrDefault();

       if (oldP != null)
       {
           PeopleData.Persons.Remove(oldP);
       }
   }
}

PeopleData.Persons in this case is a List<Person> that’s populated with some sample data.  The [EnableClientAccess] attribute causes the build-time bits to generate a client side proxy for calling the service without the client project needing a service reference.  It really makes the Silverlight and the Web projects feel like parts of the same app rather than disconnected pieces. 

The corresponding class that is generated on the client side is a DomainDataContext, which feels much like a LINQ to SQL DataContext only it’s lazy-loaded like the Astoria ones.  The GetPersons method on the server results in LoadPersons on the client, etc.  If I hadn’t implemented the Insert/Update/Delete methods on the server side, the DomainDataContext would simple behave like a read only data source.  This model works really well with the DataForm class.  If I set the ItemsSource of the DataForm to the Persons “table” in the client side data context, it will properly enable/disable the add/delete buttons depending on the capabilities of the data context.  Neat. 

Coming in future posts… hooking up the PersonDataContext to the Silverlight 3 UI, and in ASP.NET

Tuesday, 02 June 2009 15:53:18 (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, 07 May 2009

Let’s say I’ve got to the effort of creating a modal dialog or it’s equivalent in a Silverlight application.  What I would like to complete the picture is a “default” button, so that if I hit the Enter key while in a text box, the dialog will be “submitted”.  There are probably several ways of achieving this end, but I wanted something that was simple, and encapsulated in an attached property so the consumer wouldn’t have to deal with much code.  I wrote the attached property so that I could use it on text boxes like this

<TextBox x:Name="theText" VerticalAlignment="Center" Margin="10,0,10,0" 
	Grid.Row="0" my:DefaultButtonService.DefaultButton="theButton"/>

where “theButton” here is the default button I want to be pressed when the Enter key happens inside my text box.  The downside is that I have to apply this property to every text box on the page, but so be it, that seems like a relatively small price to pay.  So I got as far as finding the named button in the visual tree, but the the question was, how to “press” the button.  The Button class in Silverlight has a protected OnClick that would do the trick, if it wasn’t protected.  I could derive my own control from Button and expose the OnClick method, but ewww.  If I did that then every dialog that wanted this behavior would have to remember to use the derived Button class.  I tried reflecting over the Button and Invoking OnClick anyway, but turns out you get a security exception.  OK.  Then, thanks to a presentation Stuart gave us yesterday on Accessibility, I remembered the Automation framework in Silverlight.  That turned out to be super easy, just create an instance of ButtonAutmationPeer from the Button, then Invoke it.  Cool.

public static class DefaultButtonService
{
   public static readonly DependencyProperty DefaultButtonProperty =
       DependencyProperty.RegisterAttached("DefaultButton", typeof(string), typeof(DefaultButtonService), new PropertyMetadata(OnDefaultButtonChanged));


   public static string GetDefaultButton(DependencyObject d)
   {
       return (string)d.GetValue(DefaultButtonProperty);
   }

   /// <summary>
   /// Sets the CommandParameter property.
   /// </summary>
   public static void SetDefaultButton(DependencyObject d, string value)
   {
       d.SetValue(DefaultButtonProperty, value);
   }

   private static void OnDefaultButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   {
       TextBox tb = d as TextBox;
       if (tb != null)
       {
           tb.KeyUp += new KeyEventHandler(tb_KeyUp);
       }
   }

   static void tb_KeyUp(object sender, KeyEventArgs e)
   {
       switch (e.Key)
       {
           case Key.Enter:
               string name = (string)((DependencyObject)sender).GetValue(DefaultButtonProperty);
               object root = App.Current.RootVisual;
               object button = ((FrameworkElement)root).FindName(name);
               if (button is Button)
               {
                   ButtonAutomationPeer peer = new ButtonAutomationPeer((Button)button);

                   IInvokeProvider ip = (IInvokeProvider)peer;
                   ip.Invoke();
               }
               break;
       }
   }
}
Thursday, 07 May 2009 13:27:54 (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
# Tuesday, 07 April 2009

We just added a set of new one day classes starting in May, including “Agile in day”, Silverlight 3, and UI design patterns for WPF and Silverlight.  These are lecture-style classes that will give you an in depth look at each subject.  Like our previous Silverlight event, these are 300-400 level, technical sessions that will give you a leg up on each subject in a day.  Because they are presented lecture style, we can offer them for only $125 each, so feel free to collect the whole set. :-)  Details and registration here.  We may be adding some additional topics soon, so check back often.

Tuesday, 07 April 2009 10:41:19 (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, 04 March 2009

So yesterday I was reading Josh Smith’s WPF Apps With The Model-View-ViewModel Design Pattern article in last month’s MSDN magazine, and I really liked the sample app that he built.  It totally cleared up for me some rough edges (in my understanding) of MVVM.  Most specifically, I had been conflicted about where to put things like button click handlers.  Do you put a Click event handler in your codebehind, which just defers to the View Model?  Do you create a generic CommandBinding handler to wire up commands to your View Model’s methods?  (I’ve seen both in various examples…)  The former seems like cheating a bit on MVVM (no code behind would be ideal, it seems to me) and the latter overly complicated.  Josh’s solution is to bind the Command property of the UIElement (button, menu item, whatever) to a property of type ICommand on the View Model. 

That totally made sense to me.  No more code behind (like at all, basically) and I don’t have to build additional framework to make it happen, with the exception of coming up with an ICommand implementation.  Josh solved that with a class he calls RelayCommand, which just wraps an ICommand implementation around a delegate (or lambda) of type Action<object>, with an optional Predicate<object> to handle the CanExecute method of ICommand. 

Groovy, now my XAML knows absolutely nothing about the View Model, and it’s only links to said View Model are through data binding.

Then I got to wondering if something as easy could work in Silverlight…  The answer turned out to be almost, but not quite.  Since Silverlight controls don’t expose a Command property, you have to hook them up yourself, but otherwise it works just the same way.

So if I’ve got a page with a single button on it

CropperCapture[10]

<UserControl x:Class="SilverlightCommands.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:my="clr-namespace:SilverlightCommands"
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <Button Content="Say Hello..." VerticalAlignment="Center" 
                HorizontalAlignment="Center" 
                my:ButtonService.Command="{Binding Path=SayHello}"/>
    </Grid>
</UserControl>

I can add an attached property whose value is bound to the ICommand property on the View Model.  The attached property grabs the ICommand and hooks up the button’s click handler to the ICommand’s Execute method.

#region Command

/// <summary>
/// Command Attached Dependency Property
/// </summary>
public static readonly DependencyProperty CommandProperty =
    DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(ButtonService),
        new PropertyMetadata(OnCommandChanged));

/// <summary>
/// Gets the Command property.
/// </summary>
public static ICommand GetCommand(DependencyObject d)
{
    return (ICommand)d.GetValue(CommandProperty);
}

/// <summary>
/// Sets the Command property.
/// </summary>
public static void SetCommand(DependencyObject d, ICommand value)
{
    d.SetValue(CommandProperty, value);
}

/// <summary>
/// Handles changes to the Command property.
/// </summary>
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if (d is Button)
    {
        Button b = d as Button;
        ICommand c = e.NewValue as ICommand;
        b.Click += delegate(object sender, RoutedEventArgs arg) { c.Execute(null); };
    }
}

#endregion

In the View Model, then, is the actual handler for the command

public class PageViewModel
{
    public ICommand SayHello
    {
        get
        {
            return new RelayCommand(param => MessageBox.Show("HelloWorld"));
        }
    }
}

Note that I’m using Josh’s RelayCommand helper to wrap the simple lambda.

That feels like not too terribly much infrastructure, although I might have to create separate attached properties to handle different control types (e.g. those that don’t have a Click event).  It would be pretty straightforward to support command parameters in the same way, by creating a CommandParameter attached property and picking up its value in the OnCommandChanged handler…

private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if (d is Button)
    {
        string parameter = d.GetValue(CommandParameterProperty) as string;
        Button b = d as Button;
        ICommand c = e.NewValue as ICommand;
        b.Click += delegate(object sender, RoutedEventArgs arg) { c.Execute(parameter); };
    }
}

The only thing that doesn’t really handle well is the CanExecute method, which in WPF would automatically enable/disable the button based on the result of the ICommand’s CanExecute method.  I tried a couple ways of wiring it up during the OnCommandChanged handler, but couldn’t come up with anything that didn’t look to have nasty side-effect (garbage collection, etc.) or be just ugly.  I’d probably just bind the IsEnable property of the button to a separate boolean on the View Model and deal with it there. 

Update:

Code is here.

Wednesday, 04 March 2009 16:06:59 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [3]  | 
# Monday, 02 March 2009

After reading Justin Angel’s very good summary of unit testing Silverlight using the Silverlight UnitTest framework, RhinoMocks, Unity etc. I decided to give it a go and find out how easy it was for a “real” application.  I converted the course evaluation app I’ve been working on since December to MVVM using Unity, and then set about trying to test it with the testing tools. 

I must say I do rather like the MVVM pattern, so that part went pretty well, as did the use of Unity, although there was some learning to do there.  It’s not quite as obvious as it maybe should be, but it didn’t take too long.  The biggest issue I had with both Unity and the test tools come in relation to the WCF proxy that I’m using to talk back to the server from Silverlight.  I think it would be a bit easier using the asynchronous interface that is generated as part of the proxy (the one that has all the BeginXXX, EndXXX methods on it) but I’m using the interface that consists of completion events and XXXAsync methods.  That object (in my case it’s called “EvalServiceClient”) doesn’t like being created by Unity, presumably somewhere down in the WCF infrastructure, so I had to create it myself and register the instance with Unity.

Current = new UnityContainer();
Current.RegisterInstance(typeof(EvalServiceClient), new EvalServiceClient());

That isn’t too terrible, but it did take a while to figure out.  One of the things that makes that harder is that the errors that come back just say “Unity couldn’t create your thing” and it takes a bit of digging to find out where and why it actually failed. 

The blogosphere suggests (and I agree) that implementing MVVM in Silverlight isn’t quite as straightforward as it might be in WPF, largely due to the lack of commands.  There are a couple of declarative solutions for mapping UI elements to methods in a View Model, but most relied on quite a bit of infrastructure.  I decided it was OK (enough) to put just enough code in my code-behind to wire up event handlers to methods on the View Model.  Icky?  No too bad.  Commands would obviously be better, but there it is. 

private void submitEval_Click(object sender, RoutedEventArgs e)
{
    ViewModel.SubmitEval();
}

private void lstCourse_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    CourseInfo ci = lstCourse.SelectedItem as CourseInfo;
    ViewModel.CourseSelected(ci);
}

I found that the reliance on data binding makes it much easier to separate presentation from business logic.  The View Model can represent any UI specific logic like which buttons should be enabled when (which the underlying business/domain model doesn’t care about) and allow a designer to work strictly with XAML.  Because INotifyPropertyChanged really works, you don’t have to worry about pushing data into the interface, just on which properties have to be marked as changed.  For a computed property like “should the submit button be shown” it may take a few extra notification calls to make sure the UI gets updated properly, but that seems reasonable. 

public bool CanSubmit
{
    get
    {
        _canSubmit = (_registrationId.HasValue && _questionCategories != null);
        return _canSubmit;
    }
    set
    {
        if (_canSubmit != value)
        {
            _canSubmit = value;
            Changed("CanSubmit");
        }
    }
}

public int? RegistrationId
{
    get
    {
        return _registrationId;
    }
    set
    {
        if (_registrationId != value)
        {
            _registrationId = value;
            Changed("RegistrationId");
            Changed("CanSubmit");
        }
    }
}

public System.Collections.ObjectModel.ObservableCollection<Evaluation.EvaluationServer.QuestionCategory> QuestionCategories
{
    get
    {
        return _questionCategories;
    }
    set
    {
        if (_questionCategories != value)
        {
            _questionCategories = value;
            Changed("QuestionCategories");
            Changed("CanSubmit");
        }
    }
}

In the example above, the value of “CanSubit” relies on the state of RegistrationID and QuestionCategories, so the property setters for those properties also “invalidate” CanSubmit so the UI will update properly.  In the XAML, the IsEnabled property of the Submit button is bound to the CanSubmit property of the View Model.

The next challenge was getting the test code to work.  Because I didn’t want the test code to call the real web service, I had to mock the calls to the EvalServiceClient.  For whatever reason, I didn’t have any luck with mocking the object itself.  I think this had to do with the asynchronous nature of the calls.  The code registers an event handler for each completion event, then calls XXXAsync to call the web service.  When it returns, it fires the completion handler.  To make that work with RhinoMocks, you have to record the event hookup, then capture an IEventRasier interface that will let you raise the desired event.

using (mocks.Record())
{
    client.GetStudentNameCompleted += null;
    raiser = LastCall.IgnoreArguments().GetEventRaiser();

That call to GetEventRaiser fails if I mock the EvalServiceClient object itself, so I had to create an interface that I could mock instead.  Luckily, the generated proxy is a partial class, so it’s easy to add a new interface.

public interface IEvalServiceClient
{
    event System.EventHandler<GetStudentNameCompletedEventArgs> GetStudentNameCompleted;

    void GetStudentNameAsync();
}

public partial class EvalServiceClient : IEvalServiceClient
{

}

Now the RhinoMocks code mock the IEvalServiceClient interface, and the GetEventRaiser call works just fine.  Because the WCF client actually gets created by Unity, we have to register the new mock instance with the UnityContainer.

MockRepository mocks = new MockRepository();
IEvalServiceClient client = mocks.StrictMock<IEvalServiceClient>();

IoC.Current.RegisterInstance<IEvalServiceClient>(client);
IEventRaiser raiser;

using (mocks.Record())
{
    client.GetStudentNameCompleted += null;
    raiser = LastCall.IgnoreArguments().GetEventRaiser();

    client.GetStudentNameAsync();

}

using (mocks.Playback())
{
    Page page = new Page();
    raiser.Raise(client, new GetStudentNameCompletedEventArgs(new object[]{"Jones, Fred"}, null, false, null));
    WaitFor(page, "Loaded");
    TestPanel.Children.Add(page);

    EnqueueCallback(() => Assert.IsTrue(page.lblStudent.Text == "Jones, Fred"));

    EnqueueTestComplete();
}

During playback, we can use the IEventRaiser to fire the completion event, then check the UI to make sure the property got set correctly. 

I’m pretty convinced that MVVM is a good idea, but this method of testing seems awfully cumbersome to me, plus pretty invasive.  I had to make quite a few changes to my app to make the testing work, including creating the interface for the EvalServiceClient, and marking any controls I needed to write tests against with x:FieldModifier=”public” in my XAML.  It’s good to know how to make this work, but I’m not sure I’d use this method to test everything in my Silverlight app.  Probably only the highest risk areas, or places that would be tedious for a tester to hit.

Monday, 02 March 2009 14:42:25 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Friday, 20 February 2009

On Wednesday I posted about coming up with a way of decorating any UIElement with a red border in response to a validation error.  The only drawback (that I could see just then) was that I had to add borders to all the elements that I might want to exhibit this behavior.  Today Shaun suggested that I try it as an attached property instead, which might save that hassle.  Indeed it does.  Because of the way attached properties work in Silverlight, it’s possible to use them to attach behavior as well as data be hooking the value changed event.  Here’s the same (basically) logic as an attached property

public class ValidationService
{
    public static readonly DependencyProperty ValidationBehaviorProperty =
        DependencyProperty.RegisterAttached("ValidationBehavior", typeof(bool), typeof(ValidationService),
                                    new PropertyMetadata(OnValidationBehaviorChanged));

    public static bool GetValidationBehavior(DependencyObject d)
    {
        return (bool)d.GetValue(ValidationBehaviorProperty);
    }

    public static void SetValidationBehavior(DependencyObject d, bool value)
    {
        d.SetValue(ValidationBehaviorProperty, value);
    }

    private static void OnValidationBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is FrameworkElement)
        {
            FrameworkElement fe = d as FrameworkElement;

            if ((bool)e.OldValue)
            {

            }
            if ((bool)e.NewValue)
            {
                fe.BindingValidationError += new EventHandler<ValidationErrorEventArgs>(fe_BindingValidationError);
            }
        }
    }

    static void fe_BindingValidationError(object sender, ValidationErrorEventArgs e)
    {
        FrameworkElement fe = e.OriginalSource as FrameworkElement;
        DependencyObject parent = fe.Parent;
        Border b = null;

        if (parent is Grid)
        {
            b = new Border() { BorderBrush = new SolidColorBrush(Colors.Red), BorderThickness = new Thickness(0) };

            Grid g = parent as Grid;
            g.Children.Add(b);
            int column = (int)fe.GetValue(Grid.ColumnProperty);
            b.SetValue(Grid.ColumnProperty, column);
            int row = (int)fe.GetValue(Grid.RowProperty);
            b.SetValue(Grid.RowProperty, row);
            g.Children.Remove((UIElement)fe);
            b.Margin = fe.Margin;
            fe.Margin = new Thickness(0);
            b.Child = (UIElement)fe;
        }
        else if (parent is Border)
        {
            b = parent as Border;
        }

        if (e.Action == ValidationErrorEventAction.Added)
        {
            if (b != null)
            {
                b.BorderThickness = new Thickness(1);
            }
            ToolTipService.SetToolTip(fe, new TextBlock() { Text = e.Error.Exception.Message });
        }
        if (e.Action == ValidationErrorEventAction.Removed)
        {
            if (b != null)
            {
                b.BorderThickness = new Thickness(0);
            }
            ToolTipService.SetToolTip(fe, null);
        }
    }
}

Note that when registering the attached property, we register a value changed handler (in this case OnValidationBehaviorChanged).  This will get called the first time the property is set, which gives us an opportunity to mess with the element that the property is attached to.  If the value of the property is being set to true, we hook up the BindingValidationError handler.

In the validation error handler, we have to find out if the element is currently surrounded by a Border, and add one if it isn’t.  Note: in this example it will only work if the element is originally the child of a Grid.  This could easily be modified to support the other Panel types. 

Once the parent is a border, then the old logic from the previous example can be reused to set the border and tooltip on or off as appropriate. 

Notice that we don’t mark the BindingValidationError event as Handled so that it will bubble.  That allows us to write additional forms specific error handling higher up in the visual hierarchy.  At the form level we might want to invalidate the submit button if validation failed, or something similar, while letting the logic in the attached property handle the UI effects.

In the XAML, this new attached property can be used to attached the desired visual effect to any FrameworkElement like so

<TextBox Width="Auto" x:Name="txtNewHours"  Text="{Binding Hours, Mode=TwoWay, Converter={StaticResource hoursConverter}, 
    NotifyOnValidationError=true, ValidatesOnExceptions=true}" 
    my:ValidationService.ValidationBehavior="true"
    Grid.Row="1" Grid.Column="1" Margin="5,5,5,5"/>
Friday, 20 February 2009 15:32:07 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, 18 February 2009

I was having a bit of trouble getting validation to work during data binding in SL, but that seems to be resolved now.  I’ve got a little time tracking app, and want to be able to log new time entries…

CropperCapture[8]

I want the user to be able to enter hours only in 1/4 hour increments.  The way that gets handled in Silverlight is different from WPF.  To make it work in Silverlight the data binding source has the throw an exception if the new value is unacceptable.  In this case, the source is a “LogEntry” class that has a property “Hours” that implements INotifyPropertyChanged to support full two-way data binding.

public class LogEntry : INotifyPropertyChanged
{

    private decimal hours;
    public decimal Hours 
    {
        get
        {
            return hours;
        }
        set
        {
            if ((value % .25M) != 0)
            {
                throw new Exception("please enter time in quarter-hour increments");
            }
            if (hours != value)
            {
                hours = value;

                NotifyPropertyChanged("Hours");
            }
        }
    }

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

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

In the property setting for the Hours property, if the value isn’t evenly divisible by .25 an Exception gets thrown.  In the XAML, the binding is set up to notify (as a binding error) when an exception gets thrown

 

<TextBox Width="Auto" x:Name="txtNewHours"  Text="{Binding Hours, 
    Mode=TwoWay, 
    Converter={StaticResource hoursConverter}, 
    NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

The grid that holds all the controls handles the BindingValidationError event, which is where all the fun stuff happens…

private void newEntryGrid_BindingValidationError(object sender, ValidationErrorEventArgs e)
{
    if (e.Action == ValidationErrorEventAction.Added)
    {
        //not valid
    }
    if (e.Action == ValidationErrorEventAction.Removed)
    {
        //now it's valid
    }
}

OK, so now I know when the value isn’t valid, but what to do about it.  In WPF, the easiest thing to do would be to use a “decorator” to add a border around the UI element that failed validation, but in Silverlight we don’t get decorators.  Instead, I wrapped each item that needed to support validation in a red border with a thickness of 0 in XAML.

<Border BorderBrush="Red" BorderThickness="0">
    <TextBox x:Name="txtNewHours" Text="{Binding ...}"/>
</Border>

That’s a little extra work that I’d rather not do, but there it is.  It would be easy to wrap up this behavior in a custom control, but this was much quicker.

In the validation handler then, all we have to do is get the original source of the binding error and use the VisualTreeHelper to get it’s parent.  If that parent happens to be a border, set the border’s thickness to 1 to make it visible.  I’m also setting the tooltip for that offending control to be the message of the validation error.  If the ValidationErrorEventAction == Removed, then get rid of the tooltip and set the border’s thickness back to 0.

private void newEntryGrid_BindingValidationError(object sender, ValidationErrorEventArgs e)
{
    if (e.Action == ValidationErrorEventAction.Added)
    {
        DependencyObject ui = e.OriginalSource as DependencyObject 
        DependencyObject parent = VisualTreeHelper.GetParent(ui);
        if (parent is Border)
        {
            ((Border)parent).BorderThickness = new Thickness(1);
        }
        ToolTipService.SetToolTip(ui, new TextBlock() { Text = e.Error.Exception.Message });
    }
    if (e.Action == ValidationErrorEventAction.Removed)
    {
        DependencyObject ui = e.OriginalSource as DependencyObject 
        DependencyObject parent = VisualTreeHelper.GetParent(ui);
        if (parent is Border)
        {
            ((Border)parent).BorderThickness = new Thickness(0);
        }
        ToolTipService.SetToolTip(ui, null);
    }
}

CropperCapture[9]

That same code should work for any control that I want to do validation on, as long as I remember to add the borders in XAML. 

Wednesday, 18 February 2009 14:10:45 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Friday, 13 February 2009

Check out http://events.sftsrc.com/ for more new classes…

  • LINQ
    • 2 days of LINQ to Objects, LINQ to XML, LINQ to SQL, LINQ to Entities and more
  • ASP.NET
    • 5 days of ASP.NET including some AJAX and a hint of Silverlight
  • WPF
    • 3 days of WPF goodness
  • Silverlight
    • 2 days for those with WPF experience or
    • 3 days for web developers
  • C#  and the .NET Framework
    • 5 days of C# 3.0 and the 3.5 framework, including LINQ, extension methods and the rest of the new language features
Friday, 13 February 2009 10:17:36 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, 21 January 2009

I needed to build a survey (a course evaluation in this case, but name-your-survey…) and I wanted to be able to add new questions and question categories to the database without having to touch my (Silverlight) survey app.  I wanted the basic layout to look like this…

CropperCapture[2]

It took a little experimentation, and I’m sure there are other ways to make this work, but here’s what worked for me:

The questions and categories live in the database, like so

CropperCapture[3]

Categories contain questions, questions have text, and what we store when the survey is complete are the answers to the questions.

In the XAML, first there is an ItemsControl to deal with the categories, so that each category will have it’s own DataGrid.  The ItemsControl has a DataTemplate that defines what each category name and data grid of questions will look like (some formatting details removed for clarity)

<ItemsControl x:Name="dgPanel" >

    <ItemsControl.ItemTemplate>

        <DataTemplate>

            <StackPanel Orientation="Vertical">

                <TextBlock Text="{Binding CategoryName}"/>

                <data:DataGrid x:Name="dgOverall" ItemsSource="{Binding Questions}">

                <data:DataGrid.Columns>

                    <data:DataGridTextColumn Header="Question"

                   Binding="{Binding Text}" IsReadOnly="True"/>

                    <data:DataGridTemplateColumn Header="Rating">

                        <data:DataGridTemplateColumn.CellTemplate>

                            <DataTemplate>

                                <t:Rating UserRating="{Binding Path=Answer, Mode=TwoWay}" />

                            </DataTemplate>

                        </data:DataGridTemplateColumn.CellTemplate>

                        <data:DataGridTemplateColumn.CellEditingTemplate>

                            <DataTemplate>

                                <t:Rating UserRating="{Binding Path=Answer, Mode=TwoWay}"/>

                            </DataTemplate>

                        </data:DataGridTemplateColumn.CellEditingTemplate>

                    </data:DataGridTemplateColumn>

                </data:DataGrid.Columns>

 

            </data:DataGrid>

            </StackPanel>

        </DataTemplate>

    </ItemsControl.ItemTemplate>

</ItemsControl>

The questions come from a WCF call, and get bound in the form load

void client_GetQuestionsCompleted(object sender, GetQuestionsCompletedEventArgs e)

{

    dgPanel.ItemsSource = e.Result;

}

Each row that comes back has the category header text and a collection of questions, so that for each item in the ItemsControl, the text is bound to the header, and the questions are bound to the datagrid.  The DataGridTemplateColumn stuff above maps the Answer property of each question to a UserControl called Rating that contains the radio buttons.  Depending on which radio button gets checked, the value of the user control represents an enum value with their answer.  Because the data binding is defined as TwoWay, the user’s answers are updating in the in-memory copy of the questions, and when the user eventually hits the “Submit” button, the collection of questions (and answers) is sent back to the web service. 

Now I can add new questions to the database and have those questions show up in the survey, and previously submitted evaluations will only have answers for the questions that were present at the time the survey was submitted.  There’s still some work to do here, like setting up groups of questions so that different sets of questions could be used for different circumstances, etc, but this is a decent start.

Wednesday, 21 January 2009 10:23:06 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  |