Archive for September, 2009
WPF Diagrams: Styling a Node Element
Tagged as WPF DiagramsOne of the most powerful and useful features of WPF Diagrams is the ability to style any part of a diagram any way you want it to look and feel. One of the most common parts of a diagram that you’ll likely want to style are the node elements. When it comes to customizing the look of a node element there are 2 main things to think of first. First there is the style to be applied to the nodes, and secondly the data template that each node type should have. The data template is what seperates the look of one type of node to some other type of node. The style of all the nodes is generally the same, this is what provides a node with its MoveThumb, Resizer, and ConnectionPointThumbs. In this post we look at how to provide your own node style in your applications.
The standard DiagramNodeElement style uses a simple black colored Resizer, and blue gradient filled connection points as seen in below.

The best place to start is by copying the standard DiagramNodeElement style. Below I have provided the style used in the WPF Flow Diagrams product.
<Style x:Key="NodeStyle" TargetType="{x:Type ms:DiagramNodeElement}"> <Setter Property="FocusVisualStyle" Value="{x:Null}" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ms:DiagramNodeElement"> <Grid Canvas.Left="{TemplateBinding Left}" Canvas.Top="{TemplateBinding Top}"> <ms:MoveThumb Element="{Binding RelativeSource={RelativeSource TemplatedParent}}" Focusable="True" Clip="{TemplateBinding Geometry}" Style="{StaticResource {x:Static ms:MoveThumb.InvisibleStyleKey}}" Cursor="SizeAll" Name="Mover" /> <ms:Resizer Element="{Binding RelativeSource={RelativeSource TemplatedParent}}" Name="Resizer" /> <ContentPresenter Name="ContentPresenter" /> <ms:ConnectionPointThumb ConnectionPoint="{Binding Content.DefaultConnectionPoint, RelativeSource={RelativeSource TemplatedParent}}" Width="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}}" Height="{Binding ActualHeight, RelativeSource={RelativeSource TemplatedParent}}" IsHitTestVisible="False" Focusable="True" Visibility="Collapsed" Name="Connector" Style="{StaticResource {x:Static ms:MoveThumb.InvisibleStyleKey}}" /> <ItemsControl ItemsSource="{Binding Content.ConnectionPoints, RelativeSource={RelativeSource TemplatedParent}}" ItemTemplate="{StaticResource ConnectionPointTemplate}" Name="Connectors" Visibility="{TemplateBinding ShowConnectionPoints, Converter={StaticResource bvc}}"> <ItemsControl.RenderTransform> <TranslateTransform X="{Binding (Canvas.Left), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource Negative}}" Y="{Binding (Canvas.Top), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource Negative}}" /> </ItemsControl.RenderTransform> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <Canvas /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemContainerStyle> <Style> <Setter Property="Canvas.Left"> <Setter.Value> <MultiBinding Converter="{StaticResource CPX}"> <Binding /> <Binding Path="Formatter.Layout" RelativeSource="{RelativeSource AncestorType={x:Type ms:DiagramSurface}}" /> <Binding Path="Position" /> </MultiBinding> </Setter.Value> </Setter> <Setter Property="Canvas.Top"> <Setter.Value> <MultiBinding Converter="{StaticResource CPY}"> <Binding /> <Binding Path="Formatter.Layout" RelativeSource="{RelativeSource AncestorType={x:Type ms:DiagramSurface}}" /> <Binding Path="Position" /> </MultiBinding> </Setter.Value> </Setter> </Style> </ItemsControl.ItemContainerStyle> </ItemsControl> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="False"> <Setter TargetName="Resizer" Property="Visibility" Value="Collapsed" /> </Trigger> <Trigger Property="IsResizable" Value="False"> <Setter TargetName="Resizer" Property="Visibility" Value="Collapsed" /> </Trigger> <DataTrigger Binding="{Binding IsReadOnly, RelativeSource={RelativeSource AncestorType={x:Type ms:DiagramSurface}}}" Value="True"> <Setter TargetName="Resizer" Property="Visibility" Value="Collapsed" /> <Setter TargetName="Mover" Property="Visibility" Value="Collapsed" /> <Setter TargetName="Connector" Property="Visibility" Value="Collapsed" /> <Setter TargetName="Connectors" Property="Visibility" Value="Collapsed" /> </DataTrigger> <DataTrigger Binding="{Binding CanModifyConnectivity, RelativeSource={RelativeSource AncestorType={x:Type ms:DiagramSurface}}}" Value="False"> <Setter TargetName="Connector" Property="Visibility" Value="Collapsed" /> <Setter TargetName="Connectors" Property="Visibility" Value="Collapsed" /> </DataTrigger> <MultiDataTrigger> <MultiDataTrigger.Conditions> <Condition Binding="{Binding Path=(ms:CursorAction.Current), Converter={StaticResource CursorActionTypeConverter}, RelativeSource={RelativeSource AncestorType={x:Type ms:DiagramSurface}}}" Value="{x:Static ms:CursorActionType.CreateConnection}" /> <Condition Binding="{Binding IsReadOnly, RelativeSource={RelativeSource AncestorType={x:Type ms:DiagramSurface}}}" Value="False" /> </MultiDataTrigger.Conditions> <Setter TargetName="Mover" Property="IsHitTestVisible" Value="False" /> <Setter TargetName="Connector" Property="IsHitTestVisible" Value="True" /> <Setter TargetName="Connector" Property="Visibility" Value="Visible" /> </MultiDataTrigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
Â
Phew! That’s a lot of XAML! Good news though – you only need to tweak parts of it to start styling your own nodes.
After modifying the parts of the style that you need to customize, you then need to tell the DiagramSurface that this is the style you want to use. This is easily done by setting the NodeStyleSelector property of the IDiagramFormatter that you give to the DiagramSurface. If you wanted to use your style on all the different types of nodes in a diagram, then you would use the following code.
<ms:FixedStyleSelector x:Key="{x:Static styles:GradientStyle.NodeStyleSelectorKey}" Style="{StaticResource NodeStyle}" />So why make your own node element style?
The node element style is the best way to incorporate your own SizeThumb and ConnectionPointThumb styles on your nodes. This is done simply by making your own style for these thumbs, and then setting them on the appropriate controls found within the node element style. This allows you to achieve the effects in the following images.
![]()
Changing the color of the Resizer, and only including the corner thumbs.
![]()
Changing the look of the outbound connection point thumbs to have a transparent green fill.
Another useful tip with creating your own node styles is to add MouseDoubleClick or MouseRightButtonDown event handlers to the MoveThumb within the style. This will allow you to define appropriate actions to occur when the user double clicks or right click on a node. And since the MoveThumb in the standard node style is the most exposed control, it is the best place to attach such event handlers.
Node element styles are not limited to being applied to all the nodes in a single diagram. By using a TypeStyleSelector instead of a FixedStyleSelector, you can have some types nodes with different colored connection points compared to other nodes. Or some nodes could have the standard Resizer, while other nodes use a Resizer that only allows nodes to be square shaped.
Need any help with making your own node element styles? Drop a comment on this blog or put a post up on the forum. We’d love to hear from you!
Want to play with WPF Diagrams? Download the free trials of WPF Flow Diagrams or WPF Star Diagrams.
WPF Diagrams: Dynamic connection point creation
Tagged as WPF DiagramsIn this blog post we take a look at one of our latest additions to the WPF Diagramming product, the ability to dynamically add connection points to a node.
Say we want to design a node representing some kind of intersection in a network. The intersection has input flows and output flows. Each input and output connection should have its own connection point to make it easier to follow the diagram, rather than having all the connections bunched up on one point. To make it flexible for the user, we want to be able to have a variable number of connection points on the node. Hence we want to be able to dynamically add and remove connection points from instances of this node.
Here is how we go about implementing such a node:
1. We start by creating a new class that extends from FlowDiagramNode.
2. Include an ObservableCollection<IDiagramConnectionPoint> field to hold all the connection points. I’m calling this _connectionPoints.
3. In the constructor, we setup all the initial connection points on this node, and add them all to the observable collection as follows:
public SampleNode1() { _connectionPoints = new ObservableCollection<IDiagramConnectionPoint>(); _connectionPoints.Add(new InboundConnectionPoint(this, Edge.Top)); _connectionPoints.Add(new OutboundConnectionPoint(this, Edge.Bottom)); }
4. Now we want to override the FlowDiagramNode.ConnectionPoints property to return the observable collection.
5. As both outbound and inbound connection points are stored in the same collection, we need to implement the InboundConnectionPointsCore and OutboundConnectionPointsCore properties in a way that looks through our observable collection and picks out the appropriate points to return. One way to do this is as follows:
protected override IList<InboundConnectionPoint> InboundConnectionPointsCore { get { List<InboundConnectionPoint> result = new List<InboundConnectionPoint>(); foreach (IDiagramConnectionPoint point in _connectionPoints) { InboundConnectionPoint p = point as InboundConnectionPoint; if (p != null) { result.Add(p); } } return result; } }
6. Done!
Connection points can now be freely added or removed from the observable collection which results in dynamic connection point creation and deletion at the graphical layer. Note that the above code simply illustrates how to get dynamic connection point creation and deletion working, some more logic is required to specify when exactly the connection point collection is modified. How you add and remove connection points is up to you as it’s likely application specific. You could allow there to always be 1 unused connection point available on a node by adding or deleting connection points when connections are made or removed from the node. Or you could have a control somewhere in your application or on the node itself which the user can use to specify the number of input and output points.
Here are a couple of screenshots of one possible way dynamic connection point creation could be implemented. First we have network intersection node with one input point on the top, and one input point on the bottom as its initial state.

When the user introduces an input flow to the connection point on the top, a new input point can be added to the node as seen in the next screenshot. This will allow additional inbound connections being introduced by the user if necessary.

The WPF Diagramming products support this type of customisation because we know that nearly every application will require something different. Need to have a minimum or maximum number of connections? No problem – do whatever you require!
If you want to create some amazing diagrammatic visualizations with WPF then check out our WPF Flow Diagrams or WPF Star Diagrams products.
Many to many associations in the LightSpeed designer
Tagged as LightSpeedLightSpeed supports many-to-many associations between entities via a feature called through associations. Associations are represented by entities of a through type, which in turn maps to a through table. For example, in a media sharing site, a Contribution may have many Tags, and each Tag may be associated with many Contributions. So you’d represent this using a ContributionTag through table, but at the LightSpeed level you’d usually work directly with the Contribution.Tags and Tag.Contributions collections rather than down at the ContributionTag level. (See the documentation for more info.)
If you’re using a nightly build of LightSpeed, you can set up through associations using the designer. Just select the ThroughAssociation arrow in the toolbox and drag it between the entities you want to have a many-to-many association:
As mentioned above, a through association requires a through entity type. If LightSpeed can find an entity that has one-to-many associations to the ends of the new through association, it will guess that as the through entity. Otherwise, you need to either wire it up yourself:
or tell the designer to create the through entity (and the one-to-many associations) automatically:
Auto through entities avoid cluttering up the diagram when there’s no additional data associated with the relationship, and you don’t need fine control over database mapping, eager loading, etc. If you have an explicit through entity and it’s not adding any value, you can convert it to an auto through entity by right-clicking the through association and choosing Convert to Auto Through Entity; similarly if you have an auto through entity and find you need extra properties or more control, you can right-click the through association and choose Convert to Explicit Through Entity, and the designer will create the entity and associations ready for you to edit.
If you’re using through associations and you want to model them in the designer, grab the latest nightly build and give it a go!
Customising LightSpeed entity templates
Tagged as LightSpeedLightSpeed provides two ways of defining your entity model: writing the entity classes out in code, for maximum flexibility, or using the visual designer, to avoid spending time on boilerplate. Behind the scenes, the visual designer is just generating code according to conventional LightSpeed coding patterns. This is similar to many other visual designers — for example, the LINQ to SQL designer works in exactly the same way.
One thing that’s unusual about the LightSpeed designer, though, is that we provide access to the code generation templates, so if you want to generate code that’s different to the default, you can do so by editing the templates. These are NVelocity templates written in VTL and can be found under the installation directory, under Tools > Designer > Templates.
However, editing the templates in place has a couple of problems. First, whenever you upgrade LightSpeed, it will reinstall its templates over the top of yours. Second, if you’re working with other developers, or across multiple machines, you need to make sure the custom templates get copied to each machine.
To solve these problems, LightSpeed allows you to keep your templates with the project. By doing this, you eliminate the risk of the templates being overwritten during install, and you can treat them as part of the project rather than a machine setting — for example putting them in source control so that when another developer gets the project sources they get the current templates as well.
To do this, copy the template files from the installation location to a suitable project-specific location. Then go into Solution Explorer, select the project node and look at the Properties grid. If the project contains a LightSpeed model (a .lsmodel file), you’ll see an extra entry here called LightSpeed Template File. Edit this to point to your copy of the “main” template (typically Base.vm):
Next time you edit your model, the code will be regenerated using your template copies. You can now edit these copies to your heart’s content!
Here are a couple of tips and tricks for working with custom templates:
1. Visual Studio won’t automatically regenerate code when you change the template. Changes to the templates will only take effect next time you edit your model. If you don’t actually need to do anything to the model, just move something and move it back again — that will be enough to trigger regeneration.
2. We occasionally ship updates to the default templates, to reflect new features or options, or to fix bugs. If these updates are relevant to you, you’ll want to fold them into your custom templates. It’s therefore a good idea to keep a copy of the “Mindscape version our custom templates are based on” around. That way, when we update the templates, you can use a diff and merge tool to find the changes between the Mindscape versions and merge them into your files (or to merge your diffs from the baseline onto the new baseline). Changes to the templates are usually fairly minor, so this shouldn’t usually be too painful!
Most users won’t need to customise the templates — the default templates generate simple code that will be acceptable in most environments, especially when combined with the per-property custom coding settings — but if you have established conventions or standards that don’t match with ours then it can be a handy escape hatch. If that sounds like you, grab a copy and give it a try!
What’s new in WPF Flow Diagrams
Tagged as WPF DiagramsSince the release of our WPF Flow Diagrams product we have been getting loads of great feedback and suggestions, which we’ve been using to drive new features. Here’s a rundown of what we’ve been adding to WPF Flow Diagrams over the past few months.
Diagram Model Enhancements
In the RTM version of WPF Flow Diagrams, the set of connection points — the places where a line can connect to a node — was fixed when the node was created. We’ve now added the ability to dynamically add more connection points to a diagram node through a user action. This can be useful for various situations such as making sure that some kind of node will always have at least one available output for attaching a connection.
It is also now possible to dynamically change the positions of connection points on a diagram node. Usually, each connection point is given a relative placement on their node which is set up within the node’s constructor, but this feature enables you to override those initial placements. Check out the ConnectionPointRelocation sample, included with this product, to see how to reposition individual connection points in response to user actions.
We have added a Data property to IDiagramConnectionPoint allowing connection points to store arbitrary data if relevant for your diagrams. This can also be used to provide connection points with tool tips.
Using the new RaisesBoundsChangeRequested attached property and the BoundsChangeRequested event on DiagramNodeElement, a node can be set up to change size depending on its contents. This is useful for having a node expand when typing text into a text box or by opening up an expander situated inside a node.
New DiagramSurface features
We’ve also been adding feature to the DiagramSurface control, mostly to provide finer control over what your users can do with the diagram.
For example, if you don’t want connections to be able to latch onto other connections (for example in a loop), the new CanConnectToConnection property allows you to disable this.
We’ve also refined the “read only” behaviour. In RTM there’s a single global IsReadOnly flag, but now we’ve provided finer control via the CanAddOrRemoveNodes and CanModifyConnectivity properties to the DiagramSurface. These allow you to enable or disable node or connection creation and deletion individually.
In addition, you can now control scroll bar visibility on the DiagramSurface in the same way as you can on a ScrollViewer.
ViewModel Support
Since we released FlowDiagrams, it has been possible to use a FlowDiagramModel as a ViewModel. In order to allow the ViewModel to act solely as an observer of the business model, and thereby avoid the complications of two-way synchronisation between the ViewModel and the business model, we provided the IDiagramNodeBuilder interface so that you could translate UI “add node” actions directly into business model actions. We have since extended this with three more interfaces to allow you to translate other UI actions directly into model terms. IDiagramNodeRemover and IDiagramConnectionRemover allow you to handle the deletion of nodes and connections respectively; IDiagramConnectionRelocator allows you to handle when the user changes the connectivity of the diagram. By providing your own implementations of these interfaces, you can have these UI actions take effect on your business model and let changes flow naturally upward to the ViewModel.
All these features have been inspired by the feedback and requests from our customers. You can get them from the nightly builds builds page, and if there are any features or support that you would like with any of our products or you find a potential bug then jump into the forums and let us know. We love to hear from you and we really appreciate your feedback and suggestions!
Categories
BrainDump (1)
Community Code (4)
Events (15)
F# (11)
General (50)
Lab Samples (2)
LightSpeed (249)
MegaPack (7)
News (68)
NHibernate Designer (18)
Nightly news (40)
Phone Elements (22)
Products (87)
Projects (5)
Screencast (6)
SharePoint (3)
Silverlight (14)
Silverlight Elements (59)
SimpleDB Management Tools (20)
Visual Studio (9)
VS File Explorer (7)
Web Workbench (20)
WPF (43)
WPF Diagrams (53)
WPF Elements (91)
WPF Property Grid (32)



Posted by Jason on 29 September 2009 





