Unni's Blog

Design, Expression Blend, Silverlight, WPF, Windows Phone

"Panel-like" system

"Panel-like" system

  • Comments 21

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!

Leave a Comment
  • Please add 2 and 8 and type the answer here:
  • Post
  • I think this is a great project. It's a great start and I see it being very helpful to me. I only have one problem which I am having difficulty with. I opened your project in VS2005 (with orcas CTP) and, although the project runs, when I try to view Window1.xaml in the Design View I get errors. The first is that there is a missing assembly attribute in the first line of code. All the other errors state "type StickyPanels:PanelControl could not be found." Any help you can provide on this issue would be helpful.
  • 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!
  • This example shows how databinding can be used for displaying a set of connected nodes. To...
  • 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.
  • 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?
  • 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!
  • Sombody asked me how one could extend the "Panel-like system" such that Panels could be re-sized. Here...
  • 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

  • Do you have a VB version of this code?

  • Lesters blog at blogs.msdn.com\llobo has a much better example. It is int he form of a library - so is more useful to the users.

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

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

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

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

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

Page 1 of 2 (21 items) 12