Udostępnij za pośrednictwem


"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 removed

  • Anonymous
    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... Bajan

  • Anonymous
    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:

  1. (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.
  2. 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.