The AGT (Argentum Tela) series of articles is an effort to do two things. Usually an idea is presented only in its finished form. The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches. The second goal, and the example vehicle for the evolution aspect, is an extensible Design Surface for Silverlight similar to what we have in Visual Studio 2008. This type of application has all sorts of interesting uses. My example is a Home Theater layout tool. Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx
Yes, I changed the name of the article. Here at the 19th step, I decided to ditch the old tagline.
Visual and Code Refactoring
After letting Property Editing sit for too long, I have a list of questions to answer and things I've been meaning to fix or refactor. I publish these Refactoring articles as part of the Reality Blogging commitment but also in case some of the random code is useful to anyone. Let's get started.
I don't know why I had a corner radius on the Visual Lasso, I was probably suffering from some Web2.0itus which I am now over. I change this and changed the colors:
The lasso was also crashable by drawing diagonally until the lasso size would involve negative numbers. This is fixed.
I have gotten some questions from interested parties, which I'll answer here.
- How about a better constructor for LogMessage?
- Sure. More constructors provided
- Where is IDragDropmanager.RemoveDropTarget?
- Missing. I can be very focused trying to get these articles out sometimes. This has been added.
- In Page.xaml.cs in the example application, why are you resolving IRegionManager when the Page is the IRegionManager implementation?
- Force of habit, and I was unsure how I was going to leave that. And there's nothing wrong with talking to yourself using a Contract...
- Why are the names inconsistent between IPageView and RootPresenter ?
- Shameful inconsistency. IPageView has been renamed to IRootView.
- Why are the names of the Region Controls in Page.xaml not the same as the Regions themselves?
- More inconsistency. They are all named XXXRegion now. As I looked at this I also wondered why I was using Canvas and not a ContentPresenter, possibly something to do with how much ContentPresenter was chaning in Beta2-->RC0. At any rate, the regions have good names and I've switched to ContentPresenter.
- In IRegionManager, what is the difference between RootVisual and TopLevelContainer? Why do you need both of them?
- RootVisual is meant so that IRegionManager could provide something to System.Windows.Application.RootVisual, and matches its type of UIElement. I could probably rename this to ApplicationRootVisual since that is the only reason to have this. TopLevelContainer is used as the main Playground of services that need to do something visually, like DragDropManager. This isn't as bad as it first seems, for example the built-in "Popup" class must do something very similar. Comments have been added.
The Border on DesignSite
When is five minus five not zero? When you have applied a RenderTransform to a FrameworkElement. For the border on DesignSite, I would move the control by the border thickness (5px) when I would hide or show the border. Once you have applied a RenderTransform, though, changing a Canvas.XXXProperty by 5px no longer means 5px. I fixed this by using a transparent and normal border rather than by changing the border thickness from 0 to 5 to show selection.
Since I had to choose from a list of licenses on Codeplex (I chose MS-PL) I am removing the creative commons snippets from the code as I see them.
The Canvas does not clip its children. This means you can drag controls all over the place outside of the Design surface which is obviously undesirable.
Refactor: I extracted a MouseMoveSelection method and made it virtual so the logic was not totally hidden inside an EventHandler. This method ultimately calls MoveSelection
I needed to make a decision here, to either create a class that extends Canvas or Panel and does perform some form of clipping on its Children, or to simply implement boundaries within the DesignSurface class. For now I went with enforcing the bounds in code and snapping the selection back to a valid value.
I went back and finished implementing my original intention for the PropertyGrid, namely that it would float around with the selection and not be statically docked to the right of the surface.
Refactor: I had a TODO item to un-hack the relationship between IDesigner and DesignSite. Since IDesigner defines a Surface property of type Canvas this was mostly already done. DesignSite.DesignParent is now of type IDesigner.
Refactor: Some methods, like GetSelectionBounds(), seemed to belong more on IDesigner than DesignSite after the above change was made.
What I sought to do next was pretty vanilla: if IDesignEditorService.Visual currently had a parent, I would remove it from its parent and add it to IDesigner.Surface or IRegionManager.TopLevelContainer in a location close to the right bounds of the current selection. Control.Parent and VisualTreeHelper.GetParent both have a return type of DependencyObject. It seems there is no generic way to remove a FrameworkElement from its visual parent.
DamonPayne.AG.IoC.ControlExtensions now has a RemoveFromParent() extension method.
The PropertyGrid now floats around to be close to the current selection.
In order to set things up for some future articles, I have change the default size of the DesignSurface and the sample application. Yes, this means it won't fit on a 1024x768 screen, which apparently some people still have even in this late hour. We'll fix this in a future article but for now I wanted more room to play.
A better Toolbox
The way gestures worked in the toolbox had been bothering me, and I thought I could make it better looking anyway, a little more like Visio perhaps. I nearly introduced an external dependency on the Silverlight Toolkit, but wanted to see how to do this myself instead. Given the amount of space I'm working with, I needed to add some more furniture. I have created an area rug, which I feel really ties the room together.
I created a Control extending Panel, WrapLayoutPanel, to property postion them items in my new and improved toolbox. The MSDN documentation for MeasureOverride and ArrangeOverride was simple, but surprisingly helpful.
Here's the new and improved toolbox:
I've finally gotten around to fixing a number of things that have been bothering me, and I think the application looks a little better too. I am having a hard time deciding what to do next, and I'm afraid the next two installments are not going to be very sexy, but will be very necessary to tie all the concepts together.
The changes in this article are published as version 0.7.18, Codeplex change set 8710. While things are still very rough, I did go ahead and make this the default public release on Codeplex.
The live demo has been updated at http://www.damonpayne.com/agt