I made my first one today… and it “just worked”.
I have a bunch of Page objects that need to push buttons into a shared space in the window’s frame. How do I do this? Easy! I just define a dependency property on the root window of type IList< RoutedUICommand> and set that on any pages that need buttons… On each page, I define a RoutedUICommand for anything that page wants to handle that’s unique to the page, add a new CommandBinding to the root window, and then call SetValue(MyWindow.SupportedCommands, list). Back in the window I handle Frame.LoadCompleted, cast e.Content to a DependencyObject, then see if GetValue( MyWindow.SupportedCommands ) is null… if not, I create a button for each command in there, using the Name and Text properties to look up the appropriate resource strings for display and tooltips.
What’s this gain me? First, my pages do not care IN THE SLIGHTEST what command scheme we’re using… right click, buttons on the screen, hot keys, mnemonics, accelerators, mouse gestures, pen motions… who cares? It just gets told when the command’s invoked. THAT is the sort of flexibility I like in an application. The pages don’t need to worry how to display their commands any more, which means all the styling and configuration code for the buttons is in a single location for the entire application.
Second, I can TEST MY PAGE IN ISOLATION! Well, not quite, but the step to getting there is pretty small. I just need to push the information to create the CommandBinding object into the dependency property and have the binding handled by the host. Then, the page can run “anywhere”, such as in a test harness. Throw in some injection for the data source, and it could go into a silverlight app… portability… yay!
Third, it just feels good. No really, the degree of separation it provides to an app makes working on either side (host, page) easier and cleaner… that feels good to me.