Sunday, 26 November 2006

I encountered a rather annoying reflection exception that caused WPF dead in it's tracks during binding which I thought might be nice to share here.

The problem arises when you bind against a property and WPF (or rather: reflection) can not determine which property you actually mean. This situation can occur when you have a property on a base class and you redefine (using the 'new' keyword) that property on a class that inherits from the base class. Here is some pseudo-code:

 

public class mySpecialisation<T> : myBase { public new T myProperty { get { return (T)base.something; } } } public class myBase { public object myProperty { get { return something;} } }

As you can see, the above situation might be a convenient way to construct your classes. However, it will throw an ugly exception.
The obvious way to work-around this problem, is to make the property on the baseclass private or protected. However, in my case, I needed to get the the property through the baseclass as well. So I renamed the property in the inheritor and got rid of the exception. Kind of disappointing though!

Sunday, 26 November 2006 22:50:50 (Romance Standard Time, UTC+01:00)  #    Comments [12]  |  Trackback
 Tuesday, 21 November 2006

Although I love Xaml and the declarative person it makes me want to be, I feel even more strongly about fearless refactoring. If I fear renaming properties or moving types around, I do not refactor. And if I do not refactor regularly, my code begins to smell bad, which is a sure way to get my project featured the one place I do not want it ;-)

So, I want to refactor, but Xaml makes me reluctant to do so. We do not set bindings in code behind, but we declare them (which I think is 'good') in Xaml. Visual Studio doesn't search Xaml files for binding-paths. And so I'm left in the dark about what impact my refactoring will have. Furthermore, binding-errors do not throw exceptions, but fail gracefully, leaving a naive unittest none the wiser.

I've tried to catch the RoutedEvent 'Binding.Error' on a higher level, but it doesn't propagate.
Nor does the LoadedEvent of controls, if the control does not explicitly call some Loaded eventhandler. In this approach I thought I would be able to catch the loaded event of the control while they are being put on the screen and register their binding to be checked later. If all your controls in question do declare a Loaded handler, then you could use something like this:

EventManager.RegisterClassHandler(typeof(Control), Control.LoadedEvent,
(RoutedEventHandler)delegate(object sender, RoutedEventArgs e)
{

   // do your thing, throw an exception to let the unit test fail perhaps!
}, true );

But, like I said, this class handler will only fire if the control is already going to another Loaded event prior to this. Bummer.

Another approach would be to write a visual tree walker and question all the bindings in the screen about their status (a property of BindingExpression). This could be some trouble, but should be very do-able.

I've opted for yet another approach. I was using trusty Reflector to see how bindings work and discovered that binding errors are always shown in the output window. After some searching, it seems that even if you do not have any trace sources declared in your app.config, the visual studio debugger always switches the System.Windows.Data trace to the 'Warning'-level. And the warning level will trace a databinding error of code 35 if a binding is in error!

Well, quite an obvious solution then is to create your own trace-listener class and registering it in the app.config. To get it to work, your unit test will have to do a refresh of the Tracesources to get the traces to work: PresentationTraceSources.Refresh();

The Tracelistener:

public class UnitTestTracer : TraceListener
{
public override void Write(string message)
{
  // throw your exception to make trace fail!
}

public override void WriteLine(string message)
{
  // throw your exception to make trace fail!

}
}

And the app.config:

 

<system.diagnostics>
<sources>
  <source name="System.Windows.Data" switchValue="Warning" >
<listeners>
  <add name="unitTestListener" type="UnittestTestWPF.UnitTestTracer, UnittestTestWPF" />
</listeners>
</source>
</sources>
</system.diagnostics>

 Simple, yet effective. The more I think about it, the more I like the approach!

Tuesday, 21 November 2006 22:02:36 (Romance Standard Time, UTC+01:00)  #    Comments [4]  |  Trackback
 Saturday, 11 November 2006

The reason I haven't been blogging much lately is because I'm now heading up a team of developers that are porting a big Winform application to WPF. It's been a blast until now, but I've been too busy to blog. We're using CAB as a means to decouple logic from presentation (MVC-pattern) and one of my developers has been blogging quite heavily about it here.

Let me go into some more detail on the whole WPF experience. As I said, we are porting the client-side of a big application (about 250 screens). We're doing it as an XBAP (Xaml browser application) to enable us to easily distribute it in our intranet. Although this does force us to install a certificate (to gain full-trust), we're not seeing major drawbacks to this approach.
WPF already decouples presentation from code a great deal more then winforms do, but combining it with MVC does give it a whole new dimension. Setting up a simple screen does mean creating a few more classes then we're used to, so we're looking into using the Guidance Automation Tools (GAT) to speed-up development time.

In my honest opinion, WPF is a truly great technology. It does what it promises, but there are a few drawbacks. First of all, I do feel it's kind of slow. Resizing a screen with a lot going on, definitely feels 'heavy'. So that's a bummer (stay away from drop-shadows, they will kill your performance). Furthermore, we are starting to see some places where XAML is not cutting it. For instance, triggers lack power on the equation and multi-bindings are always &&-nd together. Also, some 'bugs', like always clearing validation-errors after a binding update-to-target.
These are all minor things and we can work-around them. It does mean a very steep learning curve for my new developers.

It was a great feeling, when I saw my designteam checking-in controlstyles and my developers not being hindered at all by their work. All the pieces fell into place and that was quite unlike my previous experiences with winforms.

Saturday, 11 November 2006 23:10:31 (Romance Standard Time, UTC+01:00)  #    Comments [2]  |  Trackback