"Panel-like" system
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!
Comments
Anonymous
February 14, 2006
The comment has been removedAnonymous
February 14, 2006
I would encourage your to try opening the project in Microsoft Expression Interactive Designer - you should be able to work with it in there. You will see the same error since the project uses a custom control which requires building your project, but once you do that, the artboard should automatically refresh.
The Orcas CTP that you are referring to (which contains a design tool for WPF code-named "Cider") is in its infancy - expect cool things from the Cider team in the near future.
Hope this helps!Anonymous
March 07, 2006
This example shows how databinding can be used for displaying a set of connected nodes. To...Anonymous
April 04, 2006
Any plans to update this to March CTP? The discussion group pointed me here for an example of panels, but I can't see it in March CTP of EID.Anonymous
April 10, 2006
I tried recreating this in the March CTP. Although I can get it to compile without errors, my panels don't drag. In fact the OnDragPanel doesn't seem to be hit at all. Am I missing a step somewhere?Anonymous
April 26, 2006
What is the purpose of the e.MouseDevice.Capture() and .Synchronize() method calls in the PanelControl class's mousebutton and mousemove event handlers? I commented them out and it appeared to have no effect on the code whatseover. Thanks!Anonymous
April 26, 2006
Sombody asked me how one could extend the "Panel-like system" such that Panels could be re-sized. Here...Anonymous
November 03, 2006
Hi, I have a question regarding "floating" windows...? To achieve something like dragging a single panel out of the main window, would it be neccessary to create a "temporary" new window object and this panel as child of that window or how would you handle this? Thanks... BajanAnonymous
December 04, 2006
Do you have a VB version of this code?Anonymous
December 25, 2006
Lesters blog at blogs.msdn.comllobo has a much better example. It is int he form of a library - so is more useful to the users.Anonymous
May 09, 2007
Hello. Good Work. How can I close a HeaderedContentControl by clicking on the button "x" ?? I try a lot of way, and it's never work.... Thank you....Anonymous
July 28, 2007
Hello, Great job ! Do you know if it's possible to place the dragged control between two others, rather than dropping it always on the end ? Thank you :-)Anonymous
October 29, 2007
hi dimitri, this is the method i used to remove the panel when you click on the button, private void Button_Click(object sender, RoutedEventArgs e) { panel = (sender as Button).TemplatedParent as PanelControl; knownParent = this.GetItemsControlContainingPanel(panel); knownParent.Items.Remove(panel); } btw, is there a way to add more than one UIElement to the content? Thanks.Anonymous
October 29, 2007
i'm sorry, what i meant in the last post was that if there's a way to put a xaml file as the input for the panel content? thanks.Anonymous
January 25, 2008
Hey Unnir, Great article, this has been very helpful. Two things I discovered:
- (To Leebert) The Mouse Capture stuff is there in case the mouse moves outside the current app window. I commented it out and ran into the bug which made me discover what the purpose was.
- Bug - if nesting the panels inside each other, the inner PanelControl will cause its parents PanelControl's events to raise as well. So, I changed the RoutingStrategy from Bubble to Direct and this fixed the problem.
Anonymous
November 26, 2008
you saved my life ;) thanks for this exampleAnonymous
January 21, 2009
PingBack from http://www.keyongtech.com/1062102-implementing-drag-and-drop-functionalityAnonymous
May 30, 2009
PingBack from http://outdoorceilingfansite.info/story.php?id=21790Anonymous
May 31, 2009
PingBack from http://outdoorceilingfansite.info/story.php?id=4154Anonymous
June 02, 2009
PingBack from http://outdoorceilingfansite.info/story.php?id=39427Anonymous
June 17, 2009
PingBack from http://patiosetsite.info/story.php?id=648