This project has moved and is read-only. For the latest updates, please go here.

Group with backcolor and caption

Oct 1, 2012 at 1:07 PM

Is it possible to have Group with given background color and with given caption (or better UserControl) at the given location? E.g. I want to have several shapes combined into a Group with gray backcolor and two lines of text (one bold, one regular) in the upper left corner of the Group. In my case this will emphasize that several Services are running within the same Computer; the first (bold) line will contain network name of the PC, the second - its description.

Oct 2, 2012 at 8:11 AM

The default group shape is designed to act mainly like a selection of multiple shapes, so it does not draw any visuals.

You can override the default implementation but I would recommend to use an aggregated shape for your purpose. Simply add the shapes to a e.g. rounded rectangle instead of adding it to a group shape. With NShapeDesigner, move the base shape to the bottom, select all shapes and choose "aggregate shapes" from the context menu.

Oct 2, 2012 at 9:35 AM

Thank you for your reply.

Will I be able to draw caption when using aggregated shape?

Oct 2, 2012 at 12:32 PM

I'm not sure what you mean by "able to draw caption" but you can aggregate (combine) all types of shapes. You can even aggregate aggregated shapes. Each shape behaves as usual - no matter if aggregated or not.

The sample projects "Raylway Network" and "Shape Aggregations" use aggregated shapes - perhaps there you will find the answer for your question...

Oct 2, 2012 at 2:11 PM
KurtHolzinger wrote:

I'm not sure what you mean by "able to draw caption" ...

"Ideal" solution for my task which I can imagine is when several shapes are placed into a "container shape" the latter having caption via its "Text" property (and maybe some other properties as well). In my case this "container" corresponds to a Computer, and its properties are NetworkName and Description. Inside this container I will place other shapes (Services).

So I wonder how can I emulate this using NShape. As far as I understand, there's no shape nesting in NShape, so probably the closest workaround would be grouping shapes (Services) together and somehow "attaching" properties NetworkName and Description to this group (Computer). The last thing (regarding properties) seems to be the main problem...

Oct 2, 2012 at 2:39 PM

"Shape nesting" is called "shape aggregation" in the NShape framework:
Putting shapes inside other shapes / adding shapes to an other shape's Children collection. You can also create templates from your aggregated "composite shapes" as you can see in the sample "Railway Network" (all houses and signal symbols are aggregated shapes).
All shapes that are (except lines) can be used as container shape and you can place as many shapes inside the container shape as you want.

Oct 3, 2012 at 11:46 AM
Edited Oct 3, 2012 at 1:43 PM

Unfortunately aggregation seems to be not the right choice for me. NShape documentation (.chm) states: "When you resize an aggregation all its constituent shapes are resized correspondingly". And such behavior is not desirable in my case.

Can you suggest some workaround?

[UPDATE] If it would be possible to (1) prevent this resizing behavior and (2) draw background and border for the whole aggregation (with some padding) - then aggregation would become the right choice, I think.

[UPDATE] You can view picture of what I'm trying to achieve here.

Oct 4, 2012 at 9:22 AM
Edited Oct 4, 2012 at 9:28 AM

You have 2 main options:

  • The 'soft way' by adjusting the security settings (see documentation "Programmer Tasks > Customizing User Access" and the sample program "Security Demo")
  • The 'hard way' by deriving your own shapes that deactivate all resize control points by overriding the "HasControlPointCapability" method:
    public override bool HasControlPointCapability(ControlPointId controlPointId, ControlPointCapabilities controlPointCapability) { 
        
    if ((controlPointCapability & ControlPointCapabilities.Resize) != 0) 
            
    return false;
        else return base
    .HasControlPointCapability(controlPointId, controlPointCapability);
    }
Oct 4, 2012 at 9:27 AM

As far as I understand, this approach will disable resizing completely. But is it possible to leave resizing enabled but (!) working as it works in case of Groups (when child shapes are not resized automatically)?

Oct 4, 2012 at 9:57 AM
Edited Oct 4, 2012 at 9:59 AM

Disabling resizing, "soft way":
This will disable resizing for the shapes with the specified security domain.

  • Please start the "Security Demo"
  • Insert two blue shapes (e.g. boxes) into the diagram
  • Click one of the blue shapes. On the left, the current permissions are shown: This shape is assigned to security domain "A" which means that the current user (Designer) has the permissions to insert, delete, layout, ... this shape.
  • As the curent user (Designer9 has no permission for change security settings, switch the current user by selecting "Administrator" from the combo box. You will notice that some more properties appea in the property grid. Among the appearing properties, there is a property "SecurityDomainName"
  • Change the property "SecurityDomainName" to 'D' and switch back to user "Designer".
  • You will notice that you will not be able to resize the shape any more. With a quick look to the permissions on the left, you will see that all permissions except "Present" are revoked.
  • The other blue shape is still assigned to security domain "A" and therefore you can still resize it while acting as user role "Designer".

Domain permissions of each "security domain" can be adjusted per user role. General permissions can be adjusted per role only.

I hope this makes things a little clearer.

 

Disabling resizing, "hard way".

If you derive your own shape (e.g. a shape "ComputerConfig") and disable resize points there, the resize points are only disabled for this shape. Create instances of this shape for all shapes that you do not want to be resized. In your case, derive "ComputerConfig" from Dataweb,NShape.GeneralShapes.Box and create it as container shape where you insert all other shapes.

Oct 4, 2012 at 10:39 AM
KurtHolzinger wrote:

Disabling resizing, "hard way".

If you derive your own shape (e.g. a shape "ComputerConfig") and disable resize points there, the resize points are only disabled for this shape. Create instances of this shape for all shapes that you do not want to be resized. In your case, derive "ComputerConfig" from Dataweb,NShape.GeneralShapes.Box and create it as container shape where you insert all other shapes.

This duplicates my previous question (see above), but nevertheless I'll ask once more (probably I was not very clear): doesn't this approach completely disable resizing of the "container" shape?! if yes, then it's not very good: who needs a shape with a fixed size???

It would be great if I could resize the "container" shape (i.e. the aggregation) but its children would remain unaffected (as it happens with groups). Is it possible?

Oct 4, 2012 at 12:11 PM

Ok, I understand. The misleading point was that groups are not resizable at all - the size of a group is defined by its contents. I thought you do not want your users to resize shapes with the mouse.

If a group is exactly what you want and the only thing that's missing is a background, why not simply adding a 'background shape' to the group?

Oct 4, 2012 at 12:27 PM
KurtHolzinger wrote:

If a group is exactly what you want and the only thing that's missing is a background, why not simply adding a 'background shape' to the group?

Hm-m... this sounds interesting... I was completely focused on the idea of a "container", i.e. I thought that I must create parent-child relations between my shapes (e.g. ComputerShape as a parent and ServiceShape as its child). However, I can simply group, say, one ComputerShape and two ServiceShape shapes - and I'll get the same visual result (if, of course, I place the service shapes inside boundaries of the computer shape). That's not as elegant as when having true parent-child relations, but... it seems to be a workaround!

Thank you for the advice!

However, I want to have corresponding model objects (ComputerModel and ServiceModel) to have true parent-child relations. I think this means that I must kind of subscribe to the grouping event (if such one exists) and in its handler analyse what's going on with the group, and depending on that - update parent-child relations of the involved models. Seems complicated... :((

Oct 4, 2012 at 3:44 PM

There is no grouping event.

Model objects relations have nothing to do with shape relations except that a shape can attach to a mode object and present its state. You can even use multiple shapes to represent the same model object.

I you are using model objects, the shapes are only the graphical representation. First, create the relations between your business objects and afterwards, you can create the shapes for the graphical representation.
Except for the template project (see documentation, "Programmer Tasks > Customizing the Toolbox"), you do not even need to store the diagrams (which may solve your storage problem).

Oct 4, 2012 at 4:54 PM
KurtHolzinger wrote:

Except for the template project (see documentation, "Programmer Tasks > Customizing the Toolbox"), you do not even need to store the diagrams (which may solve your storage problem).

Well, I need to store at least size and location of the shapes. Yes, your framework does have automatic layout feature, but... I'm not sure that automatically created layout will always be acceptable. Anyway I will have to implement my own storage which will be aware of my current database schema. I will also extend this schema to be able to store size and location - it's easy. I'm even not sure that I will somehow use the built-in concepts of Repository and Store - probably it will be easier for me to develop some custom component which will read my database and then programmatically create shapes and connections one by one, applying size/location obtained from the same database. Seems not difficult...

Thank You very much for Your help!

Apr 23, 2014 at 9:43 AM
Edited Apr 23, 2014 at 9:50 AM
KurtHolzinger wrote:
"Shape nesting" is called "shape aggregation" in the NShape framework: Putting shapes inside other shapes / adding shapes to an other shape's Children collection. You can also create templates from your aggregated "composite shapes" as you can see in the sample "Railway Network" (all houses and signal symbols are aggregated shapes). All shapes that are (except lines) can be used as container shape and you can place as many shapes inside the container shape as you want.
Hi,KurtHolzinger
I have read "shape aggregation" relative document for two days,but cann't find the solution for me.In my case,I just want to create the composite shape like "Station" in the sample "Railway Network".But I want to create the shape from my code not just from dragging and dropping.
Composite Shape I Wanted
Like the shape in the image above,I want to create the composite shape with dynamic box counts 'n'.And the parameter "N" is given when shape creating.
How can i achieve that?
Thanks.
Apr 23, 2014 at 1:22 PM
Edited Apr 23, 2014 at 1:26 PM
Hello passionli,

here are the necessary steps:
// Creating a composite shape programmatically:
//
// 1. Create the container shape which will host all child shapes
RectangleBase containerShape = 
    (RectangleBase)project.ShapeTypes["Box"].CreateInstance();
containerShape.Width = 200;
containerShape.Height = 80;
containerShape.FillStyle = project.Design.FillStyles.Red;
System.Drawing.Rectangle containerBounds = containerShape.GetBoundingRectangle(true);
//
// 2. Create child shapes and add them to the container shape
int cnt = 3;
for (int i = 0; i < cnt; ++i) {
    RectangleBase childShape = 
        (RectangleBase)project.ShapeTypes["RoundedBox"].CreateInstance();
    containerShape.Children.Add(childShape);
    // Calculate child shape position
    childShape.X = containerBounds.Left 
        + (i * containerBounds.Width / cnt) + (containerBounds.Width / cnt / 2);
    childShape.Y = containerBounds.Bottom - 5 - childShape.Height / 2;
}
//
// 3. [Optional] Create a template from the container shape
Template compositeShapeTemplate = 
    new Template(string.Format("Container for {0} boxes", cnt), containerShape);
// Insert the template into the repository (otherwise it will not be saved)
project.Repository.InsertAll(compositeShapeTemplate);
//
// 4. [Optional] Create a toolbox item
toolSetController.CreateTemplateTool(compositeShapeTemplate);
Insert the code above into the "MainForm.FillToolbox" method of the "WebVisits" demo program and start the demo.
You will see a toolbox item (on top) containing the container shape including its 3 child shapes.