Someone asked me how to implement a “panel-like” system using Expression / WPF. This led me to do a small take on Expression Interactive Designer itselfJ. Though the panel system presented here is only 1/100th as complex as our real Palette management infrastructure (and is my own code), it serves as a good example to get you started. Source for this example can be downloaded / re-used / re-implemented at will from here.
I wanted to highlight a few concepts in this example: a) How to implement a naive dragging system, b) How to create and raise your own events, c) How to do simple hit-testing in WPF so you can figure out what is under the mouse and drop into it. I also wanted to highlight the clear distinction in roles between a developer and designer (my design skills are found severely wanting at times!).
The Panels are all custom controls that extend HeaderedContentControl because we want the panels to be draggable only when clicking on the Header part and we also want the designer to be able to specify Header and Content for every Panel. It is expected (call it a contract if you will) that the designer will name one element in the template of the control to be “PART_Header”. As long as this contract is maintained, the control should work as expected; else the drag functionality simply won’t be there.
Next step is to pull out Interactive Designer (the real one!) and create the look for an individual Panel and layout the various Panels. All the Panels share the same “chrome” (consisting of the border and the close button) and this is done by applying the same template to each. Also, each Panel’ template has two ContentPresenter elements – one to render the Header (which is a string in our case), and one to render Content (which are simple images). These various panels are then added to two ItemsControl (for the left and right containers). Also, grid splitters have been used for resizing the panel columns – neat, ah?
Back to the developer role using and using VS. At this point, we have the capability to drag panels around. Now, we want to be able to drop them into other containers. Whenever a panel is dragged, it raises a custom event called “DragPanel”. Also, when the user lets go of the mouse, another event called “DropPanel” is raised. These events then bubble up to the parent Window which then performs required logic for changing containers around. One advantage of using eventing in this fashion is that I can then reuse my custom Panel class in other scenarios where I don’t really care about drop-drop and parents and such. Also, you will see the use of some simple hit-testing code to determine the ItemsControl into which a container is dropped. Personally, I don’t prefer writing low-level hit-testing code (as I have shown in the example) and I would rather use data-binding and custom controls for this purpose – this is just there for the purpose of showing the power of the platform.
Feel free to send feedback to me!