Placing items along the path of a Connection

4 posts, 0 answers
  1. Tom
    Tom avatar
    16 posts
    Member since:
    Sep 2012

    Posted 22 Jan 2013 Link to this post


    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>

  2. Francois
    Admin
    Francois avatar
    10 posts

    Posted 24 Jan 2013 Link to this post

    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.

  3. DevCraft banner
  4. Timo
    Timo avatar
    2 posts
    Member since:
    Jun 2009

    Posted 05 May 2013 Link to this post

    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
  5. Francois
    Admin
    Francois avatar
    10 posts

    Posted 08 May 2013 Link to this post

    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.

Back to Top