Diagrammer .NET Tips and Tricks Explained Through the “UML Class Diagram” Sample - Part 3

Creating a Scrollable List

In part 1 and part 2 of this series, we explained some common techniques for creating complex ILOG Diagrammer for .NET user symbols, and we used a UMLType symbol as an example.

This post will focus on the description of the List user symbol that is used to display the attributes and operations of the UML type. This List symbol is pretty general, and could be reused in other situations.

You can look at the same source code as in the previous post to follow the explanations, since the List symbol was already there.

Here are the graphic elements of the List symbol:

listsymbol.png

The symbol is made of a DockPanel that contains a StackPanel (which will in turn contain the list items), and three groups of graphic objects that make up a scrollbar (the ‘up’ button, the thumb and the ‘down’ button). We do not want to use a predefined ILOG Diagrammer for .NET VScrollBar object here because it is a little too big for including it in our UMLType symbol.

Let’s look at the code to see how the List symbol works. First, we need a property to add items to the list:

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public Collection<GraphicObject> Items
        {
            get
            {
                return stacker.Objects;
            }
        }

The Items property just returns the Objects property of the nested StackPanel, so the items of the list will be added directly to the stacker. Note the DesignerSerializationVisibility attribute that makes sure the items will be serialized even though the collection property itself is read-only.

Now, we want our list to be scrollable (vertically only to keep it simple). For this, we add another property that will define the scroll position:

        [DefaultValue(0)]
        public int ScrollPosition
        {
            get
            {
                return scrollPosition;
            }
            set
            {
                if (value != scrollPosition)
                {
                    scrollPosition = value;
                    InvalidateLayout();
                }
            }
        }

The ScrollPosition is an integer, as it specifies a number of items (not a position in pixels): this is simpler since we always want to scroll one whole item at a time.

As you can see, the ScrollPosition does not do much by itself, it just sets an internal member variable to the specified value and calls InvalidateLayout(). The idea is to use the built-in layout mechanism of Diagrammer for .NET to really do the scrolling. The InvalidateLayout() call tells Diagrammer for .NET to call the DoLayout() method of our symbol just before the symbol is next painted on the screen. This makes sure that the scrolling logic will not be executed several times unnecessarily.The DoLayout() method is overridden as follows:

        protected override void DoLayout()
        {
            dockPanel1.SuspendLayout();
            Rectangle2D bounds = new Rectangle2D(0, 0, Rectangle.Width, dockPanel1.Height);
            stacker.Bounds = bounds;
            stacker.PerformLayout();
            if (Items.Count != 0)
            {
                int pos = scrollPosition;
                if (pos >= Items.Count)
                    pos = Items.Count - 1;
                if (pos < 0)
                    pos = 0;
                bounds.Y = -Items[pos].Y;
                stacker.Bounds = bounds;
            }
            dockPanel1.ResumeLayout(true);
            UpdateArrows();
        }

What we do here is to move and resize the StackPanel that contains the items according to the ScrollPosition property and to the size of the List symbol. Basically, the top of the stacker is shifted vertically so that the item whose index is ScrollPosition is just at the top of the list. Note the SuspendLayout()/ResumeLayout() calls on the DockPanel that make sure that the parent’s layout is re-computed only once during this process. Finally, a method called UpdateArrows() is called: it enables or disables the up/down arrows according to the scroll position.

Let’s talks about the scrollbar now. The idea is simple: the ‘up’ bottom will decrease the ScrollPosition by 1, the ‘down’ button will increase it, and the thumb will modify the ScrollPosition proportionally to the move.If you look at the code,you will see that it is actually more complex than that:

  •  We added timers so that, when you keep the left mouse button pressed in the ‘up’ or ‘down’ arrows, the list continues to scroll.
  • We must ‘capture’ the mouse to make sure that, when we click in the thumb for instance, the mouse events will continue to move the thumb even if the mouse is not over it any more.

Just a final word: as it is, the List symbol is good enough as an element of the UMLType symbol, but it would need a little more polishing before it can be used as a standalone, general list object. In particular, it should behave as a container when it is used in the Visual Studio designer: see this other post that explains how to do this.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Netvouz
  • DZone
  • ThisNext
  • MisterWong
  • Wists

Tags: , ,

Leave a Reply