Sunday, May 18, 2008

Gauntlet V1 Released

Today I released V1 of Gauntlet, which is a .NET code generation tool that integrates seamlessly into your build process. I've been working away at it on and off (mainly off) for a few months now, so it felt somewhat therapeutic to finally release it.

CodeGenerationProcess

There are a wide variety of uses for Gauntlet, but here are a couple of examples:

  • Gaining control over the proxy classes generated for web / WCF services
  • Generating large parts of your domain / business layer
  • Generating constants or enumerations from sample data

Head on over to the Gauntlet CodePlex site for more information.

Thursday, May 15, 2008

Expander and VisualBrush

Today I was trying to implement some drag and drop spiffiness by including a semi-transparent preview of the item being dragged. Basically when the user starts dragging something, it "tears off" and follows the mouse cursor, so they can see exactly what they're dragging. Like I said: spiffy. Don't deny it.

Sounds like a job for VisualBrush, and indeed it is. I was able to get this working pretty nicely, but noticed a weird problem with Expanders. Basically, if you expand and then collapse an Expander, and then use a VisualBrush to clone it, the VisualBrush will clone both the header of the Expander, and the white space the Expander previously occupied when expanded.

Huh?

Let me explain with pictures. Say you've got an Expander:

image

And you then expand it, and subsequently collapse it:

image image

Then then your code creates a VisualBrush around the Expander like this:

Rect rect = new Rect(0, 0, _expander.RenderSize.Width, _expander.RenderSize.Height);
VisualBrush visualBrush = new VisualBrush(_expander);
_rectangle.Fill = visualBrush;

What you get looks like this:

image

What the...? What's happened here is what I described above. The size of the Rectangle hosting the VisualBrush is correct. However, the snapshot the VisualBrush has taken of the Expander is incorrect because it includes white-space below the header, even though the Expander is collapsed.

As I discovered, other people have come up against this problem too, but no solution was apparent. Thus, I set about to find one.

And here it is:

Rect rect = new Rect(0, 0, _expander.RenderSize.Width, _expander.RenderSize.Height);
VisualBrush visualBrush = new VisualBrush(_expander);

visualBrush.ViewboxUnits = BrushMappingMode.Absolute;
visualBrush.Viewbox = new Rect(_expander.TranslatePoint(rect.TopLeft, this), rect.Size);

_rectangle.Fill = visualBrush;

This time we get the expected result:

image

The trick is to use absolute units for the view box, and to translate the Rectangle relative to the host. This doesn't really explain the bug, but it does work around it. You can download the sample project (pictured in the images above) right about here.

Monday, April 28, 2008

Dispatcher Frames

With scant exception, WPF controls must be accessed from the same thread on which they were created. Because of this, we say they have 'thread affinity'.

In WPF, thread affinity is realised via DispatcherObjects, which can be accessed directly only on the thread on which they were created. Alternatively, they can be accessed via their Dispatcher. The Dispatcher contains methods for adding operations to a queue which is processed on the Dispatcher's thread. Each thread has at most one Dispatcher instance associated with it (which is created on demand). Many WPF classes - including controls such as TextBox and Button - inherit from DispatcherObject. This means that accessing instances of these controls must be done on the control's thread, possibly via the control's Dispatcher.

You may have noticed a type called DispatcherFrame whilst browsing MSDN (as you may be inclined to do on a Saturday night. Or not). That's what I want to discuss in this post.

You can think of a DispatcherFrame as something that forces operations to be processed until some condition is met. Every WPF application has at least one DispatcherFrame that is created when you run the application. It will continue pumping operations until the application is shut down.

At times it can be useful to pump operations until some condition of your own is met. Perhaps your code is executing on the UI thread and you want to empty the queue of operations in the Dispatcher to force control and screen updates. In the Winforms world, this is achieved via a call to Application.DoEvents(). In WPF, there is no equivalent method, but we can easily simulate one:

public static void DoEvents(this Application application)
{
    DispatcherFrame frame = new DispatcherFrame();
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new ExitFrameHandler(frm => frm.Continue = false), frame);
    Dispatcher.PushFrame(frame);
}

private delegate void ExitFrameHandler(DispatcherFrame frame);

The above code is part of a small demo project, which you can download here. It adds a DoEvents() method to WPF's Application class. The DoEvents() method adds a Background priority operation to the Dispatcher's queue, and then pushes a new frame that pumps operations until that operation is processed. As a result, all other operations that were already queued in the Dispatcher will be processed. There are several important things I need to point out here:

1. Adding the new operation to the Dispatcher is done asynchronously. As such, the operation is not processed until we call PushFrame().
2. The choice of Background as the priority is important. If we were to choose a higher priority (such as Render), then we would potentially leave lower-priority operations in the queue after the frame had exited. That's because our operation would be executed prior to those lower-priority operations, and thus we'd end the frame too soon. Perhaps there's value in adding a DoEvents() overload that accepts a minimum priority of operations that should be executed, but I haven't included one in the download.
3. Operations in a Dispatcher are not associated with a particular DispatcherFrame. A DispatcherFrame can cause any queued operation to be processed, not just those added after the frame is pushed.
4. The code assumes it is running on the thread whose Dispatcher should be pumped.

A DoEvents() implementation is nice for illustrating the utility of DispatcherFrames (indeed it is used in the MSDN documentation too), but I believe it is unnecessary. As you can see in the demo, it is possible to simulate DoEvents() in a much simpler fashion: by synchronously adding a low-priority no-op to the Dispatcher's queue:

public static void DoEvents(this Application application)
{
    Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new VoidHandler(() => { }));
}

private delegate void VoidHandler();

The call to Invoke() will not return until our operation has been processed, which won't be until all higher priority operations are processed. Therefore, the end result is the same - all queued operations are pumped (apart from those with a priority lower than Background, but I'm ignoring that in this post).

So where would you use a DispatcherFrame?

I recently had need for one at my day job. We have a splash screen that usually just shows progress information (downloading files, searching for modules etcetera) but sometimes needs to ask the user which catalog they would like to load (a catalog is just a set of modules).

The splash presenter tries as hard as it can not to ask the user (if they only have one catalog, or it has been specified via a command line switch then it doesn't need to ask), but if it does need to, it delegates a call to the splash view on the UI thread. This call needs to return the catalog that the user selected. However, it has been called on the UI thread, so obtaining a catalog from the user requires pumping operations so they can select one from a list. The code looks like this:

public Catalog SelectCatalog(ICollection<Catalog> availableCatalogs)
{
    StatusLabel = "Please select a catalog:";
    _catalogsItemsControl.ItemsSource = availableCatalogs;

    _catalogSelectionFrame = new DispatcherFrame(true);
    Dispatcher.PushFrame(_catalogSelectionFrame);

StatusLabel = "Thank you";
_catalogsItemsControl.ItemsSource = null; return _selectedCatalog; }

This method sets up the catalogs for the user to select from by assigning them to an ItemsControl (which renders each catalog as a hyperlink). It then pushes a new DispatcherFrame, which blocks until the frame is stopped. After the DispatcherFrame finishes, the selected catalog is returned. The only way to end the frame is by clicking on one of the hyperlinks representing the catalogs. Each hyperlink rendered by the ItemsControl has a Click handler as follows:

private void _hyperlink_Click(object sender, EventArgs e)
{
    _selectedCatalog = (sender as Hyperlink).DataContext as Catalog;
    _catalogSelectionFrame.Continue = false;
} 

When a hyperlink is clicked, I store the selected catalog and then end the DispatcherFrame. As a result, the code that pushed the DispatcherFrame will continue execution. Note that I would not have to manually track the selected catalog if I was using a ListBox, but for now I'm using with the ItemsControl because it was simpler to style.

Above I suggested that the only way to end the DispatcherFrame was by setting DispatcherFrame.Continue to false. That's not the entire story. DispatcherFrames may also be asked to stop during application shutdown. When that happens, DispatcherFrames will, by default, comply with the request. However, there is a constructor overload that allows you to bypass this behaviour and instead continue processing operations until your condition is met. This might be useful for a short-lived frame whose completion is critical to the correctness of your application.

Download Demo

Saturday, April 19, 2008

Berlin

Last weekend we headed to Berlin. We stayed south-east of the city, in the appropriately-named Holiday Inn. Friday night was basically a write-off, since we didn't arrive until around 10PM. On Saturday we had a late breakfast and then headed into the City.

Unfortunately, the S9 line which connected us to the centre of the city was under weekend maintenance, so it was a time-consuming process getting anywhere. This is one of the train stations we waited at (Betriebsbahnhof Schöneweide):

P4120023

P4120025

Eventually we made it into the city and headed to the Berlin Zoo, which was fantastic:

P4120031

P4120036

P4120039

P4120044

P4120060 (poor photo, but I just love black panthers. All cats want to be them)

P4130072

P4130076

P4130087

P4130094

P4130097

P4130104

P4130106

P4130109

P4130111

P4130118

On Sunday we wanted to visit Fernsehturm, which is a 365 metre high tower in central Berlin. After waiting for 40 minutes or so, we gave up because the line wasn't moving. However, here are some pictures of the tower:

P4130174

P4130183 

P4130179

The people in Berlin were very nice, and the weather was perfect. Overall it was a great weekend, although we would have liked more time to fully appreciate it.

Friday, April 18, 2008

SCSFContrib 1.5

Admittedly, it has been far too long, but the SCSFContrib team have finally released version 1.5. The highlights of this release are:

  • New Features
    • All solution and projects migrated to Visual Studio 2008 and .NET Framework 3.5.
    • DockPanelWorkspace and FormWorkspace added to SCSFContrib.CompositeUI.WinForms project.
    • Action Catalog Service added to SCSFContrib.Services project.
    • Added Visual Studio templates and Installer for Trusted and Untrusted modules in the WPF/CAB Shell.
  • New Samples
    • BankTeller implementation using a pure WPF application.
    • Demo Application with its Demo Script that provides step-by-step instructions to create a SC-SF application.
    • OrdersManager application that demonstrates how to integrate the CAB and SC-SF with Windows Workflow Foundation.
    • TestSuite reference application showing DockPanelWorkspace usage.
    • WPF CAB Shell sample application (source code, libs and unit tests).

You can head over to the SCSFContrib CodePlex site to download. Enjoy!

Wednesday, April 02, 2008

How to Waste 3 Hours on a Wednesday Afternoon

I'm playing around with the new to 3.5 System.AddIn stack at the moment. In short, it allows you to provide version tolerance between components. This is commonly used in with add-ins.

Anyways, the thing that sits between the host and add-ins is called the pipeline. It consists of a bunch of assemblies - a host view, host adapter, contracts, add-in adapter and add-in view. If the stars are aligned and the gods bestow you with grace, you will eventually get these assemblies to work.

Experiencing this pain, you may look to Pipeline Builder, a tool that helps to generate the views and adapters from the contract. That's what I did anyway. But I found that the lack of control over the generated code was causing me headaches (using templates would be nice), and the limitations of the tool mean that you'll end up with some generated code and some manually written. This wound up being way too painful to troubleshoot and maintain and I'd rather just have full control over the code for now.

Sound like a plan, Stan? Since I was taking full control over the code I thought I'd go the whole hog and refactor common functionality into helper classes. Instead of an adapter that looked like this:

public class IAddInContractToViewAddInAdapter : Contracts.AddInViews.IAddIn
{
    private Contracts.IAddInContract _contract;
    private System.AddIn.Pipeline.ContractHandle _handle;
    static IAddInContractToViewAddInAdapter()
    {
    }
    public IAddInContractToViewAddInAdapter(Contracts.IAddInContract contract)
    {
        _contract = contract;
        _handle = new System.AddIn.Pipeline.ContractHandle(contract);
    }
    public void Initialize(Contracts.AddInViews.IHost host)
    {
        _contract.Initialize(Contracts.AddInSideAdapters.IHostAddInAdapter.ViewToContractAdapter(host));
    }
    internal Contracts.IAddInContract GetSourceContract()
    {
        return _contract;
    }
}

After a bit of refactoring, I ended up with this:

public class ContractToViewAdapter_IAddIn : ContractToViewAdapterBase<IAddInContract>, IAddIn
{
    public ContractToViewAdapter_IAddIn(IAddInContract contract)
        : base(contract)
    {
    }

    public void Initialize(IHost host)
    {
        SourceContract.Initialize(Adapt.ToContract<IHost, IHostContract, ViewToContractAdapter_IHost>(host));
    }
}

Nice. The ContractToViewAdapterBase<TContract> class provides all the functionality around exposing the source contract and maintaining the ContractHandle. I also have a generic Adapt class that takes on the task of converting views to contracts and vice-versa. The Pipeline Builder generates a separate class for every contract - yuck.

Once I had taken complete control of the code I managed to reduce it in size and complexity significantly. Problem is, it didn't work. All I got was this warning:

No usable HostAdapter parts could be found in assembly "...HostSideAdapters.dll".

Um, right. My host adapter was definitely in the assembly and definitely marked with the HostAdapter attribute. So what was going on?

System.AddIn does its very best to make your life a living hell when something doesn't work. There's no trace statements, meaningful exceptions are suppressed, and if you're lucky enough to get a warning message it's usually cryptic and unhelpful. Oh, and the source and symbols for System.AddIn are not available yet, so you're on your own there, too.

After pulling some hair out I managed to figure out why my adapters weren't being found. It's because they inherit from a generic type. Yep, that's right. Even though the adapter itself is a closed type, System.AddIn spits it because I inherited from a generic type. Worse, it swallows a resultant GenericsNotImplementedException that gets thrown internally.

I got rid of the generic base class and instead implemented the corresponding generic interface manually. Now my adapters have more code in them and are harder to maintain. Stellar.

I realise this post comes across as a jab at System.AddIn. Actually, for the most part I really love the possibilities this stack yields. It just needs a lot of attention, especially in the area of diagnostics.

I've posted an issue report here.

Sunday, March 30, 2008

PS3

As a follow-up to my previous post, I bought the PS3. There were just too many positives to ignore. I got it together with Gran Turismo 5 Prologue for £300, which seemed pretty reasonable. I had to buy an HDMI cable separately, given that it doesn't come with the system. Maybe they should just ship with no cables, so consumers can save money buy getting only the cables they need.

The setup experience was seamless. I plugged the four cables in (HDMI, Ethernet, power and USB to charge the controller) and turned it on. Once I figured out how to switch my TV to HDMI input, the PS3 setup wizard was sitting there waiting for me. And - wow - did it look beautiful. Even simple text with a background animation was looking incredibly clear in HD. The setup process was straightforward and I was good to go in a couple of minutes.

Once the setup was done, the first thing I did was upgrade the firmware. This was a simple matter of going into the system menu and telling it to upgrade via the Internet. Then I sat back and waited while it upgraded the firmware from 2.01 to 2.2.

Once done, I explored the menus a little and made sure everything was configured as I expected. In doing so, I was delighted to learn that there is Bluetooth support in the PS3. That will come in handy for audio during the late-night gaming sessions, since I already own some Bluetooth headphones.

The thing that really struck me as I was looking around the menus was how fluid, intuitive and responsive they were. This is in contrast to the 360, where I often have to stare for a half second or so to comprehend which tab I'm looking at, and switching between tabs felt too slow. Someone has already recorded the PS3 menu experience here, and it's well worth a look if you haven't used a PS3 before.

The next thing I did was play some GT5. To be honest, I never liked the GT franchise because everything is so realistic . . . except crashing. It really kind of spoilt the games for me. You'd be caught up in the realism, only to hit a barrier at 200Kmph and bounce off it like you were playing bumper bowling or something.

That said, everything else about the game is outstanding. I played it a lot yesterday and plan on getting back on ASAP today (it takes a lot of willpower to write a blog post on the couch with the PS3 and TV both staring at me). I'll also be buying COD4 during the week, and jumping on GTAIV as soon as it arrives.

At some stage yesterday, I jumped on to some multi-player GT5 too. Again, everything just worked and in no time at all I was racing against people with approximately the same driving skill as myself (ie. very little).

Next up, I tried out the built-in web browser. I found it really quite usable. The lack of a keyboard (I haven't plugged in my USB keyboard yet) can make URI entry painful, but viewing pages and moving between links is really quite a good experience. You can zoom and pan with the controller, as well as move between links just by using the D-pad. All in all - good stuff.

Finally, I wanted to try out the media functionality. Remember, this is the main reason I purchased this system - to access my media. At first I found the interface a little confusing. There are top-level menu items for photos, music and video. If you go to the music menu, for example, you'll still see all folder served up by the media server, which for me includes 'Videos' and 'Photos'. Navigating into these folder just gives you a message of 'There are no tracks'. Well of course there are no music tracks in my 'Videos' directory.

I'd like to see this segregated media experience conglomerate into a single menu item: 'Media'. From there I'd like to be able to drill into specific media types or even search across my entire media library (using tags would be awesome!). For example, I could search across all media for 'London' and find all my London photos and videos (but also find London Bombs by Eskimo Joe, unless I choose not to search my music media). Hopefully this experience is fixed up a bit in a future firmware release.

I was able to view photos and listen to music straight off the bat. Awesome. However, when I tried watching video media I got a 'Media unsupported' or some such message for every video file I tried. Hmm, odd. Given that I was on firmware 2.2, all these videos should have been working. Therefore, I suspected it was an issue with my home server rather than the PS3. I tried copying those same files onto USB flash and playing directly from that stick. Doing so worked fine.

It turns out that Windows Home Server comes with Windows Media Connect 2.0, which is outdated and doesn't support DivX or Xvid. Therefore, I'd need to install Windows Media Player 11 on my WHS box in order to stream these videos to my PS3. Fair enough, but it wasn't exactly obvious how to do this because the WMP11 installer does not allow you to install on WHS. I found this thread (and specifically the post by cigga24) on the MSDN forums that lead me through the process of getting this to work. 10 minutes later I had WMP11 installed on my WHS. I tried playing the same videos on my PS3 and - lo and behold - everything worked perfectly! Moreover, the PS3 is deathly quiet, so it's a great solution for a media hub.

I'm still not a huge fan of the PS3 controller, although I have adjusted to it a little over the past day or so. I like the analog triggers on the 360 controller, especially for car games. Ideally, I'd like a 360 controller for the PS3. I see someone has already hacked this together, but this only works inside a linux installation on the PS3 not inside games. In other words, it's pretty much useless.

I haven't tried out the Blu-ray player yet. I think next weekend I'll hire Apocalypto and check it out. I have no doubt it's going to be awesome.

All in all, I'm extremely pleased with the PS3 so far. There are a few interface improvements I'd like to see, but hopefully they will be fixed with a little time. I'm also going to experiment with a linux installation and geek out a bit there.

Alright, enough typing. I'm going to play some GT5...but first, thanks to everyone for the comments in my previous post. They were very helpful indeed.

PS. I would post a picture but everything is a mess at the moment. I'm waiting for a proper TV stand, after which I will be able clean everything up.

Cardiff

A couple of weeks back I went to Cardiff with some Infusion mates (or 'buddies', as most of them would say). We went to see Wales kick French butt in the rugby final. The weather was crap, but the company and atmosphere was A+. We started early and finished late. A good time was had by all (minus the French).

I didn't post the pictures back then because - at first glance on my dinky camera screen - they looked as though they hadn't turned out. But yesterday I saw them in glorious 1080p HD via my new XBox / PS3 (I'm not telling which one I bought yet. Not sure why - I just enjoy a bit of manufactured suspense, I guess :D ). Some of the photos had actually turned out quite well, so here goes:

P3150292 (Cardiff castle - I think)

P3150293

P3150294

P3160295 (the bar was a little crowded)

P3160299

P3160302

P3160307

P3160316 (the trip back, where most everything looked like a bed)