This is a migrated thread and some comments may be shown as answers.

Placing items along the path of a Connection

3 Answers 100 Views
Diagram
This is a migrated thread and some comments may be shown as answers.
Tom
Top achievements
Rank 1
Tom asked on 22 Jan 2013, 03:26 PM

I need to display an icon along the path of a connector (see the 'A' icon in the attached image).   

Ideally, this would be closer to the start/source, rather then directly in the middle.    Is there a way to do this without setting the exact position of the content?


This is the Connector Style & Data template:

            <Style  TargetType="telerik:RadDiagramConnection" x:Key="LinkStyle" BasedOn="{StaticResource RadDiagramConnectionStyle}">
                <Setter Property="ConnectionType" Value="{Binding ConnectionType}" />
                <Setter Property="Stroke" Value="{Binding LinkLineColor, Converter={StaticResource BrushConverter}}" />
                <Setter Property="StrokeThickness" Value="{Binding StrokeThickness}" />
                <Setter Property="StrokeDashArray" Value="{Binding LinkLineStyle}" />
                <Setter Property="SourceConnectorPosition" Value="{Binding SourceConnectorPosition}" />
                <Setter Property="TargetConnectorPosition" Value="{Binding TargetConnectorPosition}" />
                <Setter Property="TargetCapType" Value="{Binding TargetCapStyle}" />
                <Setter Property="SourceCapType" Value="{Binding SourceCapStyle}" />
                <Setter Property="Foreground" Value="{Binding LinkLineColor}" />
                <Setter Property="Background" Value="{Binding LinkLineColor}" />
            </Style>


            <DataTemplate x:Key="LinkTemplate">
              <StackPanel Orientation="Vertical">
                <TextBlock Text="{Binding ConditionalRouteText}" Visibility="{Binding ConditionalRouteVisible}" />
                <telerik:RadDiagramShape  Visibility="{Binding TimeAdvanceVisible}" Geometry="M16.35,6.39 C16.28,7.36 12.26,20.45 12.26,20.45 L20.56,20.45 C20.56,20.45 16.64,7.54 16.53,6.39 z M12.30,0.50 L20.97,0.50 L32.50,33.50 L24.54,33.50 L22.23,26.16 L10.70,26.16 L8.42,33.50 L0.50,33.50 z" />
                <TextBlock Text="{Binding TimeAdvanceText}" Visibility="{Binding TimeAdvanceVisible}" />
              </StackPanel>
            </DataTemplate>

3 Answers, 1 is accepted

Sort by
0
Francois
Telerik team
answered on 24 Jan 2013, 03:17 PM
Tom,

you will need a custom connection (and template) to achieve this. The RadDiagramConnection has a variety of elements, one of which is the connection label sitting in a Canvas. So, just add an info block (or whatever design you like) in there with a name (below: StartTag):

<Style TargetType="Connections:TaggedConnection"  >
    <Setter Property="Background" Value="Transparent" />
    <!--<Setter Property="BorderBrush" Value="{StaticResource DiagramShape_Connection_BorderBrush}" />-->
    <Setter Property="Stroke" Value="DimGray" />
    <Setter Property="StrokeThickness" Value="1" />
    <Setter Property="ZIndex" Value="-1" />
 
    <Setter Property="FocusVisualStyle" Value="{x:Null}" />
 
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Connections:TaggedConnection">
                <Grid x:Name="RootTemplate">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="SelectionStates">
                            <VisualState x:Name="Selected" />
                            <VisualState x:Name="SelectedInGroup">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SelectedInGroupPath"
                                            Storyboard.TargetProperty="Visibility" Duration="0">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Unselected" />
                            <VisualState x:Name="SelectedAsGroup" />
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="EditMode">
                            <VisualState x:Name="NormalMode" />
                            <VisualState x:Name="NormalEditMode">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Duration="0"
                                            Storyboard.TargetName="NormalContent"
                                            Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Collapsed</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="EditContent"
                                            Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="TextBoxEditMode">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Duration="0"
                                            Storyboard.TargetName="NormalContent"
                                            Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Collapsed</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="EditTextBox"
                                            Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Path Stroke="{TemplateBinding Stroke}" Opacity="0.7" Fill="{TemplateBinding Background}"
                            StrokeThickness="{TemplateBinding StrokeThickness}" x:Name="DeferredPath"
                            StrokeDashArray="2 2" />
                    <Path x:Name="SelectedInGroupPath" Stroke="LightSkyBlue"
                            Visibility="Collapsed" />
                    <Path
                        StrokeDashArray="{TemplateBinding StrokeDashArray}"
                        Stroke="{TemplateBinding Stroke}" Fill="{TemplateBinding Background}"
                    StrokeThickness="{TemplateBinding StrokeThickness}" x:Name="GeometryPath" />
                    <Canvas>
                        <Border x:Name="StartTag" Background="LightYellow" BorderBrush="Orange" BorderThickness="1" Margin="10">
                            <TextBlock Text="30°"  Margin="5"/>
                        </Border>
 
                        <Grid x:Name="EdittingElement">
                            <Border Background="#00FFFFFF" />
                            <ContentPresenter x:Name="NormalContent"
                                    telerik:DiagramBehaviors.TextWrapping="Wrap"
                                    telerik:DiagramBehaviors.TextElementForeground="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=telerik:RadDiagramConnection}, Path=Foreground}" />
                            <ContentPresenter x:Name="EditContent" Visibility="Collapsed"
                                    Content="{TemplateBinding Content}"
                                    ContentTemplate="{TemplateBinding EditTemplate}" />
                            <TextBox x:Name="EditTextBox" TextWrapping="Wrap" AcceptsReturn="True"
                                    Visibility="Collapsed" Style="{StaticResource EditTextBoxStyle}" />
                        </Grid>
                    </Canvas>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

To position this element you'll need to override a method called UpdateGeometryOverride (it is called every time the geometry needs to be updated):

public class TaggedConnection:RadDiagramConnection
{
    private Border tagBlock;
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        this.tagBlock = this.GetTemplateChild("StartTag") as Border;
    }
    protected override void UpdateGeometryOverride()
    {
        base.UpdateGeometryOverride();
        if (tagBlock != null)
        {
            Canvas.SetTop(tagBlock, this.StartPoint.Y - this.Position.Y);
            Canvas.SetLeft(tagBlock, this.StartPoint.X - this.Position.X);
        }
    }
}

The Position and StartPoint are absolute coordinates with respect to the diagram canvas, hence the substraction since the template's Canvas needs a local/relative position.



Now it's just a matter of assigning whatever data or data context your business dictates to the connection and do some classic databinding. That is, replace the "30°" hardcoded in the template above with some data binding or template binding. Also, if you want to adjust the position of the tag you can alter the margins in the template or adapt the positioning (Canvas.Left and Canvas.Top) in the custom connection's code.

Hope this helps,
Francois
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Timo
Top achievements
Rank 1
answered on 05 May 2013, 03:50 PM
Hi Francois,

this is very interesting and seems to be the solution to my problem at work. But i still don't understand how to tell the diagraming framework that it should use my derived connection type (in your case the TaggedConnection) instead of a "normal" RadDiagramConnection. If you specifiy this directly in xaml this is no issue, but if using MVVM/GraphSourceBase the ItemContainers are generated by RadDiagram and i can not find a proeperty to set the ItemContainer of the connection. Can you tell me how this can be accomplished?

Edit: I think i found it: Derive your own DiagramType from RadDiagram and override GetConnectionContainerForItemOverride and IsItemItsOwnConnectionContainerOverride and return your custom connection type. Is there more to consider?

Thanks in advance,
Timo
0
Francois
Telerik team
answered on 08 May 2013, 07:43 AM
Timo,

there is an article explaining the usage of style selectors and you can find the corresponding source code on GitHub. Attached to this message you'll also find a custom version which contains the style I've given earlier. You indeed need to override the GetConnectionContainerForItemOverride method and return the TaggedConnection type in function of your bussiness data (logic).

Hope this helps,

Francois
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

Tags
Diagram
Asked by
Tom
Top achievements
Rank 1
Answers by
Francois
Telerik team
Timo
Top achievements
Rank 1
Share this question
or